2017-07-04 1 views
0

Prenez le code dans cet exemple: http://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspxLa façon la plus efficace d'ajouter plusieurs enfants à des parents par ID dans plusieurs à plusieurs dans Entity Framework Application (créer plusieurs correspondances)

Quelle serait la façon la plus efficace d'ajouter plusieurs cours à un étudiant quand j'ai les ID de cours?

Ainsi, par exemple, la fonction peut ressembler à ceci:

private static void AddCoursesToStudent(SchoolDBContext context, Student student, List<int> CourseIds) 
    {} 

Et ma tentative actuelle ressemble à ceci:

public static async Task AddCoursesToStudentAsync(SchoolDBContext context, Student student, List<int> CourseIds) 
    { 
     await context.Courses.Where(x => CourseIds.Contains(x.CourseId)).ForEachAsync(x => x.Students.Add(student)); 
     context.SaveChanges(); 
    } 

    private static void AddCoursesToStudent(SchoolDBContext context, Student student, List<int> CourseIds) 
    { 
     var task = AddCoursesToStudentAsync(context,student,CourseIds); 
     task.Wait(); 
    } 

Ce qui fonctionne, mais semble un peu bâclée, mélange en particulier dans l'async. Je pense aussi que le "Où" combiné avec le "ForEach" ramènera tous les disques quelque part.

Dans d'autres projets où il n'a pas de code d'abord nous avons habituellement un créé manuellement « MappingTable » dans ce cas ressemblerait à ceci:

public class StudentCourse 
{ 
    [Key] [Column(Order = 0)] 
    private int StudentId; 
    [Key] 
    [Column(Order = 1)] 
    private int CourseId; 

    public StudentCourse(int courseIde, int studentId) 
    { 
     StudentId = studentId; 
     CourseId = courseIde; 
    } 
} 

Et vous iriez quelque chose comme:

public static void AddCoursesToStudentMaps(SchoolDBContext context, Student student, List<int> CourseIds) 
    { 
     List<StudentCourse> maps = CourseIds.ConvertAll(courseId => new StudentCourse(courseId, student.StudentId)).ToList(); 
     context.StudentCourses.AddRange(maps); 
    } 

Ce serait bien de le faire de telle sorte que Entity Framework gère cela, peut-être que je pourrais juste créer la classe Cours des étudiants et l'ajouter au contexte? Mais cela semble aller à l'encontre du point, d'autant plus que nous en avons beaucoup de beaucoup et que le fait d'avoir créé la table de correspondance pour EF réduirait le code. Je pense juste que si EF est capable de créer le mapping automatiquement, il doit avoir un moyen de créer efficacement de nouveaux liens sans refaire le travail qu'il a fait?

Pour tester cela, je l'ai créé ce code par exemple, avec une fonction de configuration paresseux, donc si quelqu'un veut avoir une fête, cela devrait vous lever et courir:

static void Main(string[] args) 
    { 
     Run(); 
    } 

    private static void Run() 
    { 
     using (SchoolDBContext context = new SchoolDBContext()) 
     { 
      /* Run once 
      * SetUp(context); 
      */ 
      Test(context); 
      Output(context); 
     } 
    } 

    static void SetUp(SchoolDBContext context) 
    { 
     context.Students.Add(new Student() { StudentName = "Gerry" }); 
     context.Students.Add(new Student() { StudentName = "Bob" } ); 
     context.Students.Add(new Student() { StudentName = "Jane" }); 

     context.Courses.Add(new Course() { CourseName = "Science" }); 
     context.Courses.Add(new Course() { CourseName = "Math" } ); 
     context.Courses.Add(new Course() { CourseName = "History" }); 
     context.Courses.Add(new Course() { CourseName = "Other History" }); 
     context.Courses.Add(new Course() { CourseName = "Roman History" }); 
     context.Courses.Add(new Course() { CourseName = "English History" }); 
     context.Courses.Add(new Course() { CourseName = "Super History" }); 
     context.Courses.Add(new Course() { CourseName = "Tudor History" }); 
     context.Courses.Add(new Course() { CourseName = "Queen History" }); 
     context.Courses.Add(new Course() { CourseName = "King History" }); 
     context.SaveChanges(); 
    } 

    public static void Test(SchoolDBContext context) 
    { 

     var ids = context.Courses.Where(x => x.CourseName.Contains("History")).Select(x => x.CourseId).ToList(); 
     var student = context.Students.FirstOrDefault(x => x.StudentName == "Bob"); 
     AddCoursesToStudent(context, student, ids); 
    } 

    private static void Output(SchoolDBContext context) 
    { 
     OutputStudents(context); 
    } 

    private static void OutputStudents(SchoolDBContext context) 
    { 
     var allStudents = context.Students.ToList(); 
     foreach (var student in allStudents) 
     { 
      Console.WriteLine($"Student: {student.StudentName}"); 
      if (student.Courses.Any()) 
      { 
       Console.WriteLine("is enrolled on"); 
       Console.WriteLine("**************************"); 
       foreach (var contextCourseStudent in student.Courses) 
       { 
        Console.WriteLine("  " + contextCourseStudent.CourseName); 
       } 
       Console.WriteLine("************************ "); 
      } 
      Console.WriteLine("-------------------------"); 
     } 
     Console.WriteLine("Press enter to close..."); 
     Console.ReadLine(); 
    } 
    private static void OutputCourse(SchoolDBContext context) 

P.S. la raison de ne pas avoir une liste de cours est due au fait que nous avons déjà des formulaires/applications, etc., qui envoient des listes d'identifiants et, comme mentionné, il semble stupide et inefficace de sortir ces modèles de la base de données pour les ajouter au parent.

+0

Votre question a trop de texte pour une question aussi simple. Aussi, si vous avez besoin d'avoir la liste des étudiants de chaque cours, comment voulez-vous l'obtenir sans aller à la base de données pour obtenir ce cours? C'est pourquoi les relations plusieurs-à-plusieurs sont toujours modélisées avec une troisième entité. –

+0

Excuses, je voulais juste montrer travailler, mais clairement son trompeur comme vous avez mal compris ma question, je n'ai pas besoin des cours, j'ai déjà les identifiants de cours et je veux juste ajouter le "lien" qui, comme vous le dites, est généralement modélisé troisième entité, mais EF peut utilement créer cette table de liens "sous le capot" mais dans mon cas particulier à moins que j'ignore les capacités intégrées de l'EF et créer ma propre troisième entité, cela semble inefficace – chrispepper1989

Répondre

3

Je ne pense pas many-to-many avec la table de lien implicite est spécifique au code d'abord. En outre, même si cela rend l'interrogation plus facile et plus naturelle, comme vous l'avez déjà vu, elle présente des inconvénients évidents lorsque vous modifiez des liens.

Il est possible de mettre en œuvre les ajoutant de nouveaux liens efficacement à l'aide entités stub:

static void AddCoursesToStudent(SchoolDBContext context, Student student, List<int> CourseIds) 
{ 
    student.Courses = CourseIds.Select(id => context.Courses.Attach(new Course { CourseId = id })).ToList(); 
    context.SaveChanges(); 
} 

Cela fonctionne, mais sous les contraintes suivantes:

(1) Le context a été créé spécifiquement pour cet appel
(2) student est déjà attaché à la context
(3) Tous les CourseIds existent dans le d atabase
(4) Il n'y a pas Course entités chargées dans le cadre avec certains des CourseIds
(5) La collection student.Courses initiale n'est pas avide ou paresseux chargé.Cela est particulièrement d'appliquer ajouter un lien opération (vs remplacer tous les liens en déterminant les éléments ajoutés et supprimés)
(6) Vous n'utilisez pas après la context ou l'un des Course objets, parce que toutes leurs propriétés, à l'exception les PK ne sont pas réels.

Un exemple compte tenu de toutes les contraintes:

public void AddCoursesToStudent(int studentId, List<int> coursesIds) 
{ 
    using (var context = new SchoolDBContext()) 
    { 
     var student = context.Students.Find(studentId); 
     AddCoursesToStudent(context, student, coursesIds); 
    } 
} 
+0

Je me demande (peut-être bien loin), mais isn n'est-ce pas pour une relation un-à-plusieurs? Je ne suis pas sûr de savoir comment EF fait cela en interne, mais comment est-ce que l'ajout de plusieurs à un côté (c'est-à-dire assigner les cours à l'étudiant) ajoute les nombreux à l'autre côté (c'est-à-dire assigner le nouvel étudiant à chaque cours)? –

+0

1 - donc par exemple le contexte est dans un bloc utilisant, comment cela fonctionnerait-il sur un projet web? – chrispepper1989

+0

2- par cela voulez-vous dire que l'étudiant existe déjà dans la base de données, ou a été modifié dans ce contexte/spécifiquement retiré de * ce * contexte – chrispepper1989