我需要从数据库中查询。我了解如何用t-sql编写查询。真正的查询要复杂得多,但模式的简单示例如下:
SELECT * FROM [dbo].[A] AS a
LEFT JOIN dbo.[B] AS b ON a.ID = b.ParentID
LEFT JOIN dbo.[C] AS c ON y.ID = c.ParentID
LEFT JOIN
(
SELECT * FROM dbo.[D]
WHERE OtherID = @otherID
) AS d ON c.ID = d.ParentID
LEFT JOIN
(
SELECT * FROM dbo.[E]
WHERE OtherID = @otherID
) AS e ON e.ID = e.ParentID
WHERE A.ID = @Id
我需要用c#linq to sql(对于entityframework core)来编写sql,以便它生成与上面过滤的内联视图等效的视图。很明显,我们的目标是返回一个结果集,该结果集总是包含树a->b->c,并且当且仅当这些节点也匹配二次过滤时才包含d或e。注意,在内联视图中进行过滤非常容易,但是在内联视图之外进行过滤非常困难,因为在内联视图之外进行过滤往往会导致c节点在没有匹配的d子级时消失。这不是目的。
谢谢
附言:为了澄清,你可以第一次尝试将上述内容写成:
query = from a in context.A
join bt in context.B on a.ID equals bt.ParentID into btent
from b in btent.DefaultIfEmpty()
join ct in context.C on b.ID equals ct.ParentID into ctent
from c in ctent.DefaultIfEmpty()
join dt in context.D on c.ID equals dt.ParentID into dtent
from d in dtent.DefaultIfEmpty()
.Include(a => a.B).ThenInclude(b => b.C).ThenInclude(c => c.D)
.Where(a => a.ID = myPrimaryID && d.OtherId = myOtherID)
问题是,d实体上的where子句只返回d实体存在的那些行,因此如果不存在,整个堆栈将为空。如果你想说filter,其中d实体为null或者与filter匹配,如果你在这种情况下检查ef生成的sql,那么它是不正确的。正确的过滤必须发生在“join”中,就像上面的t-sql一样。
pps:是的,如果你除了父对象之外没有过滤,你可以完全省去这个,只写includes和where子句,但是我想经过思考,你会意识到,用一个术语来过滤一个伟大的孙子,但不过滤孙子是复杂的。如果你能用这两种形式写出来,我将不胜感激。
2条答案
按热度按时间m3eecexj1#
除了缺乏自然的
left outer join
语法,select
是最后一个,而且select *
需要匿名/具体类型的投影(但它可以包含整个实体),linq支持与标准sql相同的构造,包括内联子查询。因此,可以按照示例sql查询的方式编写linq查询:
由ef core翻译为:
另一种标准的linq方法是使用复合连接键将 predicate 推入连接条件(从而不过滤掉外部连接结果):
翻译为:
更紧凑的linq方法是使用相关子查询而不是联接:
ef core很高兴地将其翻译为:
最后,ef core中最紧凑和首选的方法是使用导航属性,而不是linq中的手动连接来查询实体:
ef core也将其翻译为:
wsxa1bj12#
很公平。99.9%的关于翻译左连接的ef问题都是因为没有使用导航属性。
ef core正在下一个版本中添加筛选的包含请参阅筛选包含在ef core中。
或者您可以投影一个,以及选定的子集合,如下所示: