2013-07-20 28 views
1

这个问题在stackoverflow上已经被问了好几次了,而且我已经阅读了至少六个这样的内容,但是我无法绕过简单的多给很多linq连接查询。这是我的数据库EDMX enter image description here如何做Linq多到多加入或不加导航属性

我只是试图用学生列表以及每个学生的主题填充一个WPF数据网格。

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

因此(无论是C#/ VB.net)查询像

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

感谢您的任何帮助,其如此简单的查询,但我有点卡住

+0

为什么你不只是在你的'Student'模型添加另一个属性,获取他的主题,以便主题自动加载? – sed

回答

1

一个常规的L​​INQ连接应该做的伎俩。下面是一个简化的测试案例:

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 
+0

thx为您的详细答案,恐怕我得到“名称ss不在等于左侧的范围”错误....:( –

+0

@iAteABug_And_iLiked_it:这个例子应该在一个全新的项目中工作,你正在使用哪个版本的VS和.NET框架?我使用VS 2010 + .NET 4.0在一个全新的控制台应用程序中进行了测试 – Neolisk

+0

我在VS2012,与.net 4.5 ....也许我做错了什么...明天我会花更多的时间,看看我能找出问题。thx –

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

thx ...不幸的是,这只给了我一个学生名称以及他们各自的ID名单,它不会获取主题:( –

+0

@iAteABug_And_iLiked_it奇怪,我只是测试它,并为我工作的很好 – sed

+0

我'我会在明天花更多的时间在这个项目上,尝试使用上面的解决方案或者你的解决方案...... thx –

2

如果从表StudentsSubject删除Id场然后从模型中删除该表并更新你的模型,EF会自动将这个表有两种导航性能SubjectsStudents分别为StudentSubject实体。

如果你必须离开StudentsSubject表架构完整,您可以使用Include()方法来获得学生和他们的臣民:

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

随着“正常”的导航属性,你可以写:

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

有时您需要组装大图,然后Include()和延迟加载会影响性能。有这种情况下的小窍门:

// 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藏品都充满了roots

这是加入冗余(包括或连接)和几个db请求之间的折衷,以及请求的复杂性不断增加。

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

据我知道现在EF工作正常载有()和父节点的条件可以用Contains()取代:

// load root entities 
var roots = dbContext.Parents.Where(root => %root_condition%).ToList(); 

var rootIds = new List<int>(roots.Select(root => root.Id)); 

// load entities one level lower 
dbContext.DependentEntities.Where(dependent => %dependent_condition% && rootIds.Contains(dependent.RootId)).ToList();