2011-06-06 33 views
28

mi proyecto actual se basa en Entity Framwork con código primero. Tengo tres tipos: Tarea, Tipo de Tarea y Módulo.Entity Framework crea objetos de clave externa en lugar de usar los que ya están disponibles

public class Task 
    { 
     public int ID { get; set; } 
     public Module Module { get; set; } 
     public TaskType Type { get; set; } 
    } 

    public class TaskType 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 
    } 

    public class Module 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 
    } 

Existen relaciones de clave foránea definidas dentro de la tabla para el tipo de tarea.

Mi problema es que cuando trato de crear un nuevo objeto Tarea vinculado a objetos TaskType y Module ya disponibles (ID = 1), esos objetos se crean como nuevas filas en sus tablas correspondientes.

 TaskRepository repo = new TaskRepository(); 

     Task task = new Task(); 
     task.Module = Modules.SingleOrDefault(m => m.ID == 1); 
     task.Type = TaskTypes.SingleOrDefault(t => t.ID == 1); 

     Tasks.Add(task); 

Esto crea una nueva fila en mi TaskType-mesa y en mi Módulos de mesa, así en lugar de usar los ya disponibles TaskType-ID y Módulo-ID.

espero haber dejado claro cuál es mi problema ;-)

Gracias de antemano por su ayuda. Lo aprecio.

Saludos, Kevin

+1

¿Está utilizando la misma instancia de contexto para cargar 'Module' y' TaskType' y guardar 'Task'? –

+0

No, recibo Module y TaskType usando métodos de ayuda dentro de otra clase que nuevamente contiene una instancia de mi DbContext. – bitfrickler

Respuesta

58

Si no se utiliza la misma instancia de contexto para cargar entidades relacionadas no se puede simplemente añadirlos a la nueva entidad y esperar que se utilizarán los registros existentes en la base de datos. El nuevo contexto no sabe que estas instancias existen en la base de datos; debe decirlo en el contexto.

Soluciones:

  1. Use el mismo contexto para ambas entidades relacionadas cargar y guardar la nueva entidad
  2. No cargue las entidades relacionadas y utilizar objetos ficticios
  3. entidades de carga desde el primer contexto y desprenderlos , adjuntar entidades a un nuevo contexto y luego asignarlas a una nueva entidad.
  4. Después de añadir una nueva entidad con relaciones cambiar manualmente estado de las relaciones de Added a Unchanged

Ejemplo de 1:

var module = context.Modules.SingleOrDefault(m => m.ID == 1); 
var taskType = context.TaskTypes.SingleOrDefault(t => t.ID == 1); 

Task task = new Task(); 
task.Module = module; 
task.Type = taskType; 

context.Tasks.Add(task); 

Ejemplo para 2:

var module = new Module { Id = 1 }; 
var taskType = new TaskType { Id = 1 }; 

context.Modules.Attach(module); 
context.TaskTypes.Attach(taskType); 

Task task = new Task(); 
task.Module = module; 
task.Type = taskType; 

context.Tasks.Add(task); 

Ejemplo para 3 :

var module = otherContext.Modules.SingleOrDefault(m => m.ID == 1); 
otherContext.Entry(module).State = EntityState.Detached; 

var taskType = otherContext.TaskTypes.SingleOrDefault(t => t.ID == 1); 
otherContext.Entry(taskType).State = EntityState.Detached; 

context.Modules.Attach(module); 
context.TaskTypes.Attach(taskType); 

Task task = new Task(); 
task.Module = module; 
task.Type = taskType; 

context.Tasks.Add(task); 

Ejemplo de 4:

var module = otherContext.Modules.SingleOrDefault(m => m.ID == 1); 
otherContext.Entry(module).State = EntityState.Detached; 

var taskType = otherContext.TaskTypes.SingleOrDefault(t => t.ID == 1); 
otherContext.Entry(taskType).State = EntityState.Detached; 

Task task = new Task(); 
task.Module = module; 
task.Type = taskType; 

context.Tasks.Add(task); 

context.Entry(module).State = EntityState.Unchanged; 
context.Entry(taskType).State = EntityState.Unchanged; 
+2

Guau, esa es una respuesta increíble :-) Muchas gracias. Creo que tomaré # 3 ... – bitfrickler

+0

Necesario para usar el mismo contexto y también la misma instancia del mismo contexto. Eso es importante. –

5

Soy nuevo marco de la entidad, pero me acabo de encontrar con el mismo problema, donde fue poblada mi propiedad clave externa sino el objeto de navegación era nula, con un código como:

public class EntryRecord 
{   
    [Key] 
    public int Id { get; set; } 
} 
public class QueueItem 
{  
    [Key] 
    public int Id { get; set; } 


    public int EntryRecordId { get; set; } 

    [ForeignKey("EntryRecordId")] 
    public EntryRecord EntryRecord { get; set;} 

}

al establecer la propiedad de navegación para correcciones virtuales del problema y permite la carga diferida:

[ForeignKey("EntryRecordId")] 
    public virtual EntryRecord EntryRecord { get; set;} 
Cuestiones relacionadas