2011-08-16 26 views
12

Tengo una tabla de usuario. hay referencias a esta tabla de otras tablas para campos como CreatedBy.No se puede insertar la clave duplicada en el objeto 'dbo.User'. R nLa sentencia ha finalizado

El problema es que cuando inserto una fila de otra tabla (digamos 'x'), intenta insertar un nuevo usuario en la tabla de usuarios.

Lo que debería hacer es insertar una fila en la tabla 'x' con CreatedBy como el usuario existente.

Usando Entity Framework 4. ¿Alguien se ha enfrentado a un problema como ese anteriormente?

+0

pregunta relacionada: http://stackoverflow.com/questions/5449724/entity-framework-code-first-cannot-insert-duplicate-key-in-object-db – Stefan

Respuesta

31

Puede insertar una entidad junto con entidades relacionadas o puede insertar una entidad sin las entidades relacionadas, solo haciendo referencia a las existentes. Depende del código que escribas.

Ejemplo 1:

User user = GetUserFromSomewhere(); 
using (var context = new MyContext()) 
{ 
    Order order = new Order(); 
    order.CreatedBy = user; 

    context.Orders.AddObject(order); 
    // will put both order and related entity user into Added state 
    // because user is not attached to the context 

    context.SaveChanges(); 
    // creates new order and new user and sets the relationship between them 
} 

Ejemplo 2:

using (var context = new MyContext()) 
{ 
    User user = context.Users.SingleOrDefault(u => u.Id == 1); 
    // query attaches this user to this context 
    // user is in state Unchanged now 

    Order order = new Order(); 
    order.CreatedBy = user; 

    context.Orders.AddObject(order); 
    // will put the order into Added state but doesn't touch the 
    // state of already attached related entities -> user remains 
    // in state Unchanged 

    context.SaveChanges(); 
    // creates new order with reference to user, but doesn't create new user 
} 

Ejemplo 3:

User user = GetUserFromSomewhere(); 
using (var context = new MyContext()) 
{ 
    context.Users.Attach(user); 
    // we attach explicitely to the context telling EF thereby 
    // that we know that this user exists in the DB 
    // user is in state Unchanged now 

    Order order = new Order(); 
    order.CreatedBy = user; 

    context.Orders.AddObject(order); 
    // will put the order into Added state but doesn't touch the 
    // state of already attached related entities -> user remains 
    // in state Unchanged 

    context.SaveChanges(); 
    // creates new order with reference to user, but doesn't create new user 
} 

Editar

Ejemplo 4:

int userId = GetUserIdFromSomewhere(); 
using (var context = new MyContext()) 
{ 
    var user = new User { Id = userId }; 
    // we create a stub user entity with the correct primary key 
    // It's not necessary to set other properties 
    // to only set the relationship to the order 

    context.Users.Attach(user); 
    // we attach explicitely to the context telling EF thereby 
    // that we know that this user exists in the DB 
    // user is in state Unchanged now 

    Order order = new Order(); 
    order.CreatedBy = user; 

    context.Orders.AddObject(order); 
    // will put the order into Added state but doesn't touch the 
    // state of already attached related entities -> user remains 
    // in state Unchanged 

    context.SaveChanges(); 
    // creates new order with reference to user, but doesn't create new user 
} 
+0

Excelente deducción de mi problema. Solo que ya estaba haciendo el Ejemplo 3. La única diferencia es que en lugar de obtener el usuario a través de GetUserFromSomeWhere(); Estaba pasando el objeto del usuario como un parámetro ... sobre el cable WCF ... Así que estaba perdiendo el contexto. Esto provocaba que Entity Framework también insertara el objeto de usuario. Como no sabía que ya existe. Tendría que enviar identificadores del cliente y obtener usuarios basados ​​en los identificadores en el lado del servidor. O tendría que incluir columnas de clave externa en el modelo ... para poder hacer esto ... order.CreatedBy.Id = id; –

+2

@Nilotpal: 'GetUserFromSomeWhere()' era de alguna manera una simulación de un servicio WCF, o generalmente que su entidad 'user' está separada del contexto en el que realiza las modificaciones. Usar una propiedad de clave externa es generalmente una buena idea. Alternativamente, también puede trabajar con una entidad de usuario "stub" y adjuntar esto al contexto: 'var user = new User {Id = userId}; context.Users.Attach (usuario); '. Para 'Adjuntar' solo es importante que se establezca la propiedad de la clave principal. Las otras propiedades pueden permanecer vacías cuando solo desea establecer la relación con el orden. Ver el ejemplo 4 en mi sección Editar arriba. – Slauma

+1

@Slauma - +1. Excelentes ejemplos. –

Cuestiones relacionadas