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

发布于 2024-09-03 07:44:47 字数 1925 浏览 1 评论 0原文

我试图弄清楚如何在 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对象的句柄(即它是父级的空Group对象)。

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

注意:表名称和现实世界的表示纯粹是为了这个示例而派生的,但它们的关系简化了我想要做的事情。

I am trying to figure out how to do a mixed-join in LINQ with specific access to 2 LINQ objects. Here is an example of how the actual TSQL query might look:

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

At the end, basically what I would like is an enumerable object full of GroupEntry objects. What am interested is the last two tables/objects in this query. I will be displaying Groups as a group header, and all of the Entries underneath their group heading. If there are no entries for a group, I still want to see that group as a header without any entries. Here's what I have so far:

So from that I'd like to make a function:

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);
        }
    }
}

The example above does not work quite as expected. There are 2 problems that I have not been able to solve:

  1. I still seem to be getting an INNER JOIN instead of a LEFT JOIN on the last join. I am not getting any empty results, so groups without entries do not appear.

  2. I need to figure out a way so that I can fill in the default values for blank sets of entries. That is, if there is a group without an entry, I would like to have a mostly blank entry returned, except that I'd want the EntryID to be null or 0, the GroupID to be that of of the empty group that it represents, and I'd need a handle on the entry.Group object (i.e. it's parent, empty Group object).

Any help on this would be greatly appreciated.

Note: Table names and real-world representation were derived purely for this example, but their relations simplify what I'm trying to do.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

望笑 2024-09-10 07:44:47

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

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

This is untested, but I think it's pretty close:

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;

I don't think you need to use into unless you're planning to do some further processing, such as DefaultIfEmpty(). And notice that the second overload of DefaultIfEmpty() allows you to enter a custom default value. So, you can create a new GroupEntry object and assign the values you want for each property (or leave properties blank).

她比我温柔 2024-09-10 07:44:47
  //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;
  //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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文