代码之家  ›  专栏  ›  技术社区  ›  Peter Ruderman

如何强制LINQ to SQL对可为空的外键执行内部联接?

  •  2
  • Peter Ruderman  · 技术社区  · 14 年前

    我有一个非常简单的设置。表“Node”有一个可以为空的外键“ObjectId”。这在我的数据库模型中用一对多关联表示。现在,我要运行一个查询,该查询为我提供具有特定对象id的所有节点对象

    SELECT Node.*, Object.*
    FROM Node INNER JOIN Object
        ON Node.ObjectId = Object.ObjectId
    WHERE Node.ObjectId = @objectId
    

    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();
    ...
    

    令人沮丧的是林肯 总是

    从表面上看,这似乎是有道理的。ObjectId外键可以为空,因此某些节点将没有关联的对象。但在我的查询中,我提供了一个对象id,我对没有关联对象的节点不感兴趣。

    在这种情况下,内部连接是正确的做法,但如何说服LINQ呢?

    4 回复  |  直到 14 年前
        1
  •  2
  •   Ocelot20    14 年前

    我想你只需要让它成为一个左外连接。我想象当表达式树被转换成SQL时,join和equality谓词被认为是结果查询的独立部分。换言之,左外连接就在那里,因为您是在一个可以为空的外键上连接的,而等式部分是在后面写的(可以这么说)。

    不翻译你想要的东西真的重要吗?当您使用LINQ to SQL时,您并不总是能够获得最有效的查询,这是一种公认的折衷方案。如果你没有做任何疯狂的事情,并且如果你 真正地 认为这会影响性能或其他方面,您可以编写LINQ to SQL可以使用的存储过程。

        2
  •  0
  •   Amy B    14 年前
    loadOptions.LoadWith<DataNode>(node => node.DataObject); 
    

    你误解了这句话的意思。它不会以任何方式过滤结果。它不会被转换成可以以任何方式过滤结果的sql。内部连接将过滤结果集,而左连接不会,因此左连接是正确的选择。

    如果要筛选节点,应使用包含筛选条件的查询:

    from node in context.DataNodes  
    where node.ObjectId == objectId  
    where node.DataObject != null
    select node
    

        3
  •  0
  •   Peter Ruderman    14 年前

    我最终找到了一个很好的解决办法。答案是让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();
    
        //...
    }
    
        4
  •  0
  •   SchmitzIT    11 年前

    我觉得你想要的东西很复杂。

    from n in context.Nodes join o in context.Objects on n.ObjectId 
        equals o.Object_id select n