如何做Linq多对多加入有或没有导航属性

时间:2013-07-20 20:05:08

标签: c# vb.net visual-studio-2010 linq

这个问题已经在stackoverflow上被多次询问了,我已经阅读了至少其中的六个,但我无法理解简单的多对多linq连接查询。这是我的数据库EDMX enter image description here

我只是尝试使用学生列表以及每个学生的科目来填充WPF数据网格。

现在我知道我们可以简单地使用导航属性,而不是进行连接,但是我无法获得正确的结果

所以(C#/ VB.net)查询如

var listOfStudents= // get a list with all students , along with each student's subjects

感谢您的帮助,这么简单的查询,但我有点卡住了

3 个答案:

答案 0 :(得分:3)

var listOfStudents = db.Student.Select(x => new { Id = x.Id, Name = x.StudentName, Subjects = x.StudentsSubjects.Select(y => y.Subject) });

答案 1 :(得分:2)

如果您从表Id中删除StudentsSubject字段,然后从模型中删除此表并更新您的模型,EF会自动将此表转换为两个导航属性Subjects和{{ 1}}分别用于StudentsStudent个实体。

如果您必须保持StudentsSubject表格架构完好无损,您可以使用Subject方法获取学生及其科目:

Include()

使用“普通”导航属性,您可以编写以下内容:

var students = dbContext.Students.Include("StudentsSubject.Subject")

有时您需要组装大型图形,然后包含Include(),延迟加载会影响性能。这种情况有一个小技巧:

var students = dbContext.Students.Include("Subjects")

现在为// switch off for performance DbContext.Configuration.AutodetectChangesEnabled = false; // load root entities var roots = dbContext.Parents.Where( root => %root_condition%).ToList(); // load entities one level lower dbContext.DependentEntities.Where( dependent => dependent.Root%root_condition% && %dependent_condition%).ToList(); // detect changes dbContext.ChangeTracker.DetectChanges(); // enable changes detection. DbContext.Configuration.AutodetectChangesEnabled = true; 填写了root.Dependents个集合。

以下是加入冗余(包括或加入)与多个数据库请求之间的权衡以及请求日益复杂的情况。

加入节点的“包含”数据是重复的,因此包含链可以产生从数据库到客户端的巨大流量 使用第二种方法,每个级别都要求Where()中的所有较高级别的过滤条件,并且EF生成具有第N级别的N-1个连接的查询,但是没有冗余的位置。

据我所知,EF现在可以正常使用Contains(),父节点的条件可以用roots代替:

Contains()

答案 2 :(得分:1)

常规的LINQ连接应该可以解决问题。这是一个简化的测试用例:

Public Class Student
  Public Property Id As String
  Public Property StudentName As String
  Public Property GPA As String
End Class

Public Class StudentsSubject
  Public Property SubjectId As String
  Public Property StudentId As String
  Public Property Id As String
End Class

Public Class Subject
  Public Property Id As String
  Public Property SubjectName As String
End Class

Sub Main()
  Dim students As New List(Of Student)
  students.Add(New Student With {.Id = "1", .GPA = "GPA1", .StudentName = "John"})
  students.Add(New Student With {.Id = "2", .GPA = "GPA2", .StudentName = "Peter"})

  Dim subjects As New List(Of Subject)
  subjects.Add(New Subject With {.Id = "100", .SubjectName = "Maths"})
  subjects.Add(New Subject With {.Id = "200", .SubjectName = "Physics"})

  Dim studentsSubject As New List(Of StudentsSubject)
  studentsSubject.Add(New StudentsSubject With {.Id = "10", .StudentId = "1", .SubjectId = "100"})
  studentsSubject.Add(New StudentsSubject With {.Id = "20", .StudentId = "1", .SubjectId = "200"})
  studentsSubject.Add(New StudentsSubject With {.Id = "30", .StudentId = "2", .SubjectId = "100"})

  Dim listOfStudents = From st In students
                       Join ss In studentsSubject On ss.StudentId Equals st.Id
                       Join sb In subjects On ss.SubjectId Equals sb.Id
                       Select st.StudentName, st.GPA, sb.SubjectName
End Sub