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

时间:2010-05-30 05:16:06

标签: 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]
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);
        }
    }
}

上面的示例并不像预期的那样有效。有两个问题我无法解决:

  1. 我似乎仍然在最后一次加入时获得INNER JOIN而不是LEFT JOIN。我没有得到任何空的结果,因此没有条目的组不会出现。

  2. 我需要弄清楚一种方法,以便我可以填写空白条目集的默认值。也就是说,如果有一个没有条目的组,我希望返回一个大部分空白的条目,除了我希望EntryID为null或0,GroupID是它所代表的空组的ID ,我需要一个entry.Group对象的句柄(即它的父对象,空组对象)。

  3. 对此的任何帮助将不胜感激。

    注意:表名和真实世界的表示纯粹是为了这个例子而得到的,但它们之间的关系简化了我想要做的事情。

2 个答案:

答案 0 :(得分:0)

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

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对象,并为每个属性分配所需的值(或将属性保留为空白)。

答案 1 :(得分:0)

  //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;