我的设置非常简单。表“节点”具有可为空的外键“ObjectId”。这在我的数据库模型中表示,具有一对多关联。现在,我想运行一个查询,它给我所有具有特定对象ID的节点对象。在直接的SQL中,这很容易:
SELECT Node.*, Object.*
FROM Node INNER JOIN Object
ON Node.ObjectId = Object.ObjectId
WHERE Node.ObjectId = @objectId
但现在我想在LINQ to SQL中做同样的事情:
private static Func<MyDataContext, string, IQueryable<DataNode>> _queryGet =
CompiledQuery.Compile(
(MyDataContext context, string objectId) =>
(from node in context.DataNodes
where node.ObjectId == objectId
select node));
var loadOptions = new DataLoadOptions();
loadOptions.LoadWith<DataNode>(node => node.DataObject);
context.LoadOptions = loadOptions;
DataNode node = _queryGet.Invoke(context, objectId).FirstOrDefault();
...
令人沮丧的是,LINQ 总是为此查询生成LEFT OUTER JOIN,而我尝试的任何内容都没有什么区别。
从表面上看,这似乎有道理。 ObjectId外键可以为空,因此某些节点不具有关联对象。但在我的查询中,我正在提供一个对象ID。我对没有关联对象的节点不感兴趣。
在这种情况下,INNER JOIN是正确的做法,但我如何说服LINQ?
答案 0 :(得分:2)
我认为你只需要让它成为左外连接。我想当表达式树被转换为SQL时,连接和等式谓词被认为是结果查询的单独部分。换句话说,LEFT OUTER JOIN就在那里,因为你加入了一个可以为空的外键,并且之后写了相等的部分(可以这么说)。
它没有翻译你想要的东西真的很重要吗?当您使用LINQ to SQL时,您并不总能获得最有效的查询这一事实是一种可接受的权衡。大多数情况下,如果你没有做任何疯狂的事情,查询是非常有效的,如果你真的认为它会影响性能或其他什么,你总是可以编写LINQ to SQL可以使用的存储过程
答案 1 :(得分:1)
我最终找到了一个很好的解决方案。答案是简单地让LINQ to SQL脱离困境。像这样:
using (MyDataContext context = CreateDataContext())
{
// Set the load options for the query (these tell LINQ that the
// DataNode object will have an associated DataObject object just
// as before).
context.LoadOptions = StaticLoadOptions;
// Run a plain old SQL query on our context. LINQ will use the
// results to populate the node object (including its DataObject
// property, thanks to the load options).
DataNode node = context.ExecuteQuery<DataNode>(
"SELECT * FROM Node INNER JOIN Object " +
"ON Node.ObjectId = Object.ObjectId " +
"WHERE ObjectId = @p0",
objectId).FirstOrDefault();
//...
}
答案 2 :(得分:0)
loadOptions.LoadWith<DataNode>(node => node.DataObject);
你误解了这句话的目的。它不会以任何方式过滤结果。它不会被转换为可以以任何方式过滤结果的sql。 INNER JOIN将过滤结果集,而LEFT JOIN则不会,因此LEFT JOIN是正确的选择。
如果要过滤节点,则应使用包含过滤条件的查询:
from node in context.DataNodes
where node.ObjectId == objectId
where node.DataObject != null
select node
当objectId为null(查询转换器不检查objectId的值)时,请考虑我们的查询之间的差异。
答案 3 :(得分:0)
对于我认为你想要的东西似乎非常复杂。
我会像这样强制加入:
from n in context.Nodes join o in context.Objects on n.ObjectId
equals o.Object_id select n