LINQ帮助:混合联接和指定默认值

LINQ帮助:混合联接和指定默认值,linq,join,set,default,Linq,Join,Set,Default,我试图弄清楚如何在LINQ中使用对2个LINQ对象的特定访问进行混合联接。以下是实际TSQL查询的外观示例: SELECT * FROM [User] AS [a] INNER JOIN [GroupUser] AS [b] ON [a].[UserID] = [b].[UserID] INNER JOIN [Group] AS [c] ON [b].[GroupID] = [c].[GroupID] LEFT JOIN [GroupEntries] AS [d] O

我试图弄清楚如何在LINQ中使用对2个LINQ对象的特定访问进行混合联接。以下是实际TSQL查询的外观示例:

SELECT
  *
FROM
  [User] AS [a]
INNER JOIN
  [GroupUser] AS [b]
ON
  [a].[UserID] = [b].[UserID]
INNER JOIN
  [Group] AS [c]
ON
  [b].[GroupID] = [c].[GroupID]
LEFT JOIN
  [GroupEntries] AS [d]
ON
  [a].[GroupID] = [d].[GroupID]
WHERE [a].[UserID] = @UserID
最后,基本上我想要的是一个充满GroupEntry对象的可枚举对象。我感兴趣的是这个查询中的最后两个表/对象。我将显示组作为组标题,以及组标题下的所有条目。如果某个组没有条目,我仍然希望将该组视为没有任何条目的标题。以下是我目前掌握的情况:

因此,我想做一个函数:

public void DisplayEntriesByUser(int user_id)
{
    MyDataContext db = new MyDataContext();

    IEnumberable<GroupEntries> entries =
    (
        from user in db.Users
        where user.UserID == user_id
        join group_user in db.GroupUsers
          on user.UserID = group_user.UserID
        into a

        from join1 in a
        join group in db.Groups
          on join1.GroupID equals group.GroupID
        into b

        from join2 in b
        join entry in db.Entries.DefaultIfEmpty()
          on join2.GroupID equals entry.GroupID
        select entry
    );


    Group last_group_id = 0;
    foreach(GroupEntry entry in entries)
    {
        if (last_group_id == 0 || entry.GroupID != last_group_id)
        {
            last_group_id = entry.GroupID;
            System.Console.WriteLine("---{0}---", entry.Group.GroupName.ToString().ToUpper());

        }
        if (entry.EntryID)
        {
            System.Console.WriteLine("    {0}: {1}", entry.Title, entry.Text);
        }
    }
}
上面的例子并不像预期的那样有效。有两个问题我无法解决:

我似乎仍然得到一个内部连接,而不是最后一个连接的左连接。我没有得到任何空结果,因此没有条目的组不会出现

我需要找到一种方法,这样我就可以为空白条目集填写默认值。也就是说,如果有一个没有条目的组,我希望返回一个大部分为空的条目,除了我希望EntryID为null或0,GroupID为它所代表的空组的ID,并且我需要条目上的句柄。group对象,即它的父对象,空组对象

在此方面的任何帮助都将不胜感激


注意:表名和真实世界的表示形式纯粹是为了这个示例而派生的,但它们之间的关系简化了我的工作。

这是未经测试的,但我认为非常接近:

var groupEntries =   
    from
        u in db.Users
    where
        user.Id == user_id
    join
        gu in db.GroupUsers
        on u.UserId equals gu.UserId
    join
        g in db.Groups
        on gu.GroupId equals g.GroupId
    join
        ge in db.GroupEntries
        on u.GroupdId equals ge.GroupId
        into ges
    from
        ge in ges.DefaultIfEmpty(new GroupEntry { EntryId = 0, GroupId = g.GroupId })
    select
        ge;

我认为您不需要使用into,除非您计划进行一些进一步的处理,例如DefaultIfEmpty。请注意,DefaultIfEmpty的第二个重载允许您输入自定义默认值。因此,您可以创建一个新的GroupEntry对象,并为每个属性指定所需的值,或者将属性留空。

非常感谢Dan。这是一个更直接的查询。我在后面的代码中遇到了一些麻烦。我当前的函数需要一个IEnumberable对象类型,通过它可以进行迭代。现在,在我的foreach循环中,在查询之后,我得到了用于查询运算符“DefaultEmpty”错误的不受支持的重载。另一方面,如果在linq中使用into关键字,它是否必须在较低的db层创建子查询?Corey,这是LinqToSql查询吗?Yessir。基础数据库是MSSQL 2005服务器。您应该能够通过将鼠标悬停在debugger.Negative中的groupEntries上,准确地看到发送到SQL server的查询。相反,我看到的是类似于条目|{System.Data.Linq.DataQuery}。在我的实际代码中,我有一个类似于public static IEnumerable getEntriesbyUserIDit user_id{}的函数,这就是实际查询的位置。即使我在return语句之前插入了throw Exceptiondebug point行,我仍然会在我的foreach循环中得到相同的错误,我假设是因为计算延迟:查询运算符“DefaultEmpty”使用了不支持的重载。你能告诉我这个错误的性质吗?嗨,大卫。关于最后两部分,我必须承认这有点超出我的理解。您在这里使用的是匿名函数lambda表达式吗?您是否愿意快速解释一下这里发生了什么,或者提供一个可能有助于解释的快速链接?提前谢谢。
  //set this to see all queries issued.
myDC.Log = Console.Out;

  //setup to load the GroupEntries property of each group
DataLoadOptions o = new DataLoadOptions();
o.LoadWith<Group>(g => g.GroupEntries);
myDC.LoadOptions = o;

  //query to get the groups
IQueryable<Group> groupQuery =
  from g in myDC.Groups
  where g.GroupUsers.Any(gu => gu.User.UserID == user_id)
  select g;