31 votes

Entity Framework crée des objets de clé étrangère au lieu d'utiliser ceux qui sont déjà disponibles.

Mon projet actuel est basé sur le code-first d'Entity Framwork. J'ai trois types : Task, TaskType et Module.

    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; }
    }

Il existe des relations de clé étrangère définies dans la table pour le type de tâche.

Mon problème est que lorsque j'essaie de créer un nouvel objet Task lié à des objets TaskType et Module (ID = 1) déjà disponibles, ces objets sont créés comme de nouvelles lignes dans leurs tables correspondantes.

        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);

Cela crée une nouvelle ligne dans ma table des types de tâches et dans ma table des modules, au lieu d'utiliser simplement les ID des types de tâches et les ID des modules déjà disponibles.

J'espère avoir clairement exposé mon problème ;-)

Merci d'avance pour votre aide. Je vous en remercie.

Regards, Kevin

62voto

Ladislav Mrnka Points 218632

Si vous n'utilisez pas la même instance de contexte pour charger les entités connexes, vous ne pouvez pas simplement les ajouter à la nouvelle entité et espérer que les enregistrements existants dans la base de données seront utilisés. Le nouveau contexte ne sait pas que ces instances existent dans la base de données - vous devez le dire au contexte.

Solutions :

  1. Utiliser le même contexte pour le chargement des entités liées et pour l'enregistrement de la nouvelle entité.
  2. Ne pas charger les entités liées et utiliser des objets fictifs.
  3. Charger les entités du premier contexte et les détacher, attacher les entités à un nouveau contexte et ensuite les assigner à une nouvelle entité.
  4. Après avoir ajouté une nouvelle entité avec des relations, changez manuellement l'état des relations de Added a Unchanged

Exemple pour 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);

Exemple pour 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);

Exemple pour 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);

Exemple pour 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;

7voto

Etienne Points 241

Je suis nouveau dans le cadre de l'entité, mais je viens de rencontrer le même problème, où ma propriété de clé étrangère a été remplie, mais l'objet de navigation était nul, avec un code comme celui-ci :

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;}

}

Le fait de définir la propriété de navigation comme virtuelle résout le problème et permet le chargement paresseux :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X