2010-09-03 7 views
6

me encontré con un problema que intenta actualizar un campo de clave externa:¿Cómo actualizo una clave foránea de manera eficiente en LINQ to SQL/SQLMetal?

record.ForeignId = newId; 

bombardea con "Operación no es válida debido al estado actual del objeto", debido a que el código SQLMetal lanza System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException().

que no era la primera en llegar este tema:

LinqToSQL Error : Operation is not valid due to the current state of the object y http://social.msdn.microsoft.com/forums/en-US/linqtosql/thread/f9c4a01a-195a-4f2b-a1cb-e2fa06e28b25/ analizar el caso, entre otros.

Su solución es la siguiente:

record.Foreign = Database.Foreigns.Single(c => c.Id == newId); 

Eso, por supuesto provoca una búsqueda de base de datos de Asuntos Exteriores sólo para tener una espalda objeto que tiene el Id Ya sé! Entonces, ¿cómo logro esta actualización sin la consulta inútil (o las consultas si tengo muchas de estas FK)?

Respuesta

3

Puede actualizar una instancia del padre (con el Id. Correcto), Attach en el contexto de datos como el estado de registro existente, luego asigne la propiedad Principal de su objeto hijo.

Aquí hay algo de código:

int theId = 5; 
Parent p = new Parent() { Id = theId}; 
dc.Parents.Attach(p); 
child.Parent = p; 
+0

No sabía de Attach(), pero lo intenté y obtuve un error de clave duplicada: "No se puede agregar una entidad con una clave que ya está en uso". ¿Hizo una consulta al DB para averiguarlo, o fue ese registro tal vez solo colgando en mi contexto de datos ...? –

+0

DataContext realiza un seguimiento de todos los registros que ha cargado (por clave principal). Si ha cargado un Parent con Id = 5, no podrá adjuntar otra instancia de Parent con Id = 5. –

+0

¿Y hay alguna forma de ver si uno está en caché y pescarlo si lo hace? ¿Y de lo contrario desmotar uno nuevo como en tu respuesta? ¿O tal vez le dices que deje caer la que tiene primero? O cualquier cosa para hacer que este esquema funcione? –

1

No resuelve el problema, sino una manera de obtener parcialmente alrededor de la carga adicional es comprobar para ver si el valor existente es diferente que el nuevo valor. Si es diferente, incurrirá en la consulta. Algo así como -

if(obj.PropertyID != newValue){ 
    obj.Property = PropertyClass.Load(newValue) 
} 
0

que tenía el mismo problema. Creé una solución rápida, probablemente no la mejor solución (ya que podría afectar el rendimiento), pero funcionó para mí.

En mi solución, tengo una clase con mi DataContext declarado en el nivel de clase, por lo que puedo usarlo en todas partes.

En mi solución, todo lo que quería hacer (similar a usted) fue cambiar un ID de tipo de cuenta a un ID de tipo de cuenta diferente (en la base de datos estos son FK) para un usuario.

Como DataContext ya estaba cargado, no permitía el cambio. El trabajo alrededor?

Creé una función donde creo una nueva instancia de DataContext, ejecuto mi consulta LINQ, envío los cambios y luego elimino el DataContext.

Cuestiones relacionadas