我认为父母和孩子不太适合作为独立的实体。孩子也可以是父母,通常孩子有两个父母(父亲和母亲),所以这不是最简单的上下文。但我假设你只是有一个简单的 1:n 关系,就像我使用的以下主从模型一样。
您需要做的是创建left outer join(该答案使我走上了正确的道路)。这样的连接有点棘手,但这里是代码
var query = from m in ctx.Masters
join s in ctx.Slaves
on m.MasterId equals s.MasterId into masterSlaves
from ms in masterSlaves.Where(x => x.Age > 5).DefaultIfEmpty()
select new {
Master = m,
Slave = ms
};
foreach (var item in query) {
if (item.Slave == null) Console.WriteLine("{0} owns nobody.", item.Master.Name);
else Console.WriteLine("{0} owns {1} at age {2}.", item.Master.Name, item.Slave.Name, item.Slave.Age);
}
这将在 EF 4.1 中转换为以下 SQL 语句
SELECT
[Extent1].[MasterId] AS [MasterId],
[Extent1].[Name] AS [Name],
[Extent2].[SlaveId] AS [SlaveId],
[Extent2].[MasterId] AS [MasterId1],
[Extent2].[Name] AS [Name1],
[Extent2].[Age] AS [Age]
FROM [dbo].[Master] AS [Extent1]
LEFT OUTER JOIN [dbo].[Slave] AS [Extent2]
ON ([Extent1].[MasterId] = [Extent2].[MasterId]) AND ([Extent2].[Age] > 5)
请注意,重要的是在连接集合的年龄上执行附加的 where 子句,而不是在 from 和 select 之间。
编辑:
如果您想要分层结果,您可以通过执行分组来转换平面列表:
var hierarchical = from line in query
group line by line.Master into grouped
select new { Master = grouped.Key, Slaves = grouped.Select(x => x.Slave).Where(x => x != null) };
foreach (var elem in hierarchical) {
Master master = elem.Master;
Console.WriteLine("{0}:", master.Name);
foreach (var s in elem.Slaves) // note that it says elem.Slaves not master.Slaves here!
Console.WriteLine("{0} at {1}", s.Name, s.Age);
}
请注意,我使用匿名类型来存储分层结果。你当然也可以像这样创建一个特定的类型
class FilteredResult {
public Master Master { get; set; }
public IEnumerable<Slave> Slaves { get; set; }
}
然后将该组投影到此类的实例中。如果您需要将这些结果传递给其他方法,这会更容易。