关于c#:左连接Linq查询

left join in Linq query

我正在尝试执行左联接,而不是LINQ查询中的内部联接。我已经找到了与使用DefaultIfEmpty()相关的答案,但我似乎无法使其发挥作用。以下是LINQ查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from a in dc.Table1
join e in dc.Table2 on a.Table1_id equals e.Table2_id
where a.Table1_id == id
orderby a.sort descending
group e by new
{
    a.Field1,
    a.Field2
} into ga
select new MyObject
{
    field1= ga.Key.Field1,
    field2= ga.Key.Field2,
    manySubObjects = (from g in ga select new SubObject{
                                                        fielda= g.fielda,
                                                        fieldb= g.fieldb
                                                        }).ToList()
}).ToList();

查询只给出表1中表2中有相应记录的行。我希望将表1中的每个记录填充到myObject中,并为每个myObject在manysubobjects中列出一个0-N对应记录的列表。

更新:我试着回答下面提到的"可能重复"的问题。现在我有了下面的代码,它为表1中的每个项目提供了一条记录,即使没有表2记录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from a in dc.Table1
join e in dc.Table2 on a.Table1_id equals e.Table2_id into j1
from j2 in j1.DefaultIfEmpty()
where a.Table1_id == id
orderby a.sort descending
group j2 by new
{
    a.Field1,
    a.Field2
} into ga
select new MyObject
{
    field1= ga.Key.Field1,
    field2= ga.Key.Field2,
    manySubObjects = (from g in ga select new SubObject{
                                                        fielda= g.fielda,
                                                        fieldb= g.fieldb
                                                        }).ToList()
}).ToList();

但是,使用此代码,当表2中没有记录时,我将"manysubobject"作为一个列表,其中有一个"subobject",其中包含"subobject"属性的所有空值。我真正想要的是,如果表2中没有值,"manysubobjects"为空。


我想你想要的结果可以用groupjoin()给出。

下面的代码将生成这样的结构

field1,field2,listnull if empty

样例代码

1
2
3
4
5
6
7
8
9
10
 var query = dc.Table1.Where(x => Table1_id == id).OrderBy(x => x.sort)
                .GroupJoin(dc.Table2, (table1 => table1.Table1_id), (table2 => table2.Table2_id),
                    (table1, table2) => new MyObject
                                        {
                                            field1 = table1.Field1,
                                            field2 = table1.Field2,
                                            manySubObjects = (table2.Count() > 0)
                                                ? (from t in table2 select new SubObject { fielda = t.fielda, fieldb = t.fieldb}).ToList()
                                                : null
                                        }).ToList();

dotnefiddle链接

更新

从你的评论我看到了这个

1
ga.Select(g = > new SubObject(){fielda = g.fielda, fieldb = g.fieldb})

我认为应该是(取决于"GA"是如何构建的)

1
ga.Select(g => new SubObject {fielda = g.fielda, fieldb = g.fieldb})

请用整个查询更新您的问题,这将有助于解决问题。

**更新bis**

1
2
3
4
5
6
7
8
9
 sentEmails = //ga.Count() < 1 ? null :
              //(from g in ga select g).FirstOrDefault() == null ? null :
             (from g in ga select new Email{
                  email_to = g.email_to,
                  email_from = g.email_from,
                  email_cc = g.email_cc,
                  email_bcc = g.email_bcc,
                  email_subject = g.email_subject,
                  email_body = g.email_body }).ToList()

应该是:

1
2
3
4
5
6
7
8
9
 sentEmails = //ga.Count() < 1 ? null :
             ((from g in ga select g).FirstOrDefault() == null) ? null :
             (from g in ga select new Email{
                  email_to = g.email_to,
                  email_from = g.email_from,
                  email_cc = g.email_cc,
                  email_bcc = g.email_bcc,
                  email_subject = g.email_subject,
                  email_body = g.email_body }).ToList()

检查组是否有第一个,如果没有,则该组没有任何记录,因此操作。时间戳的名称没有可发送的电子邮件。如果第一个不为空,则循环抛出group元素并创建电子邮件列表,


为了响应您的更新,要创建空列表,您可以在分配manySubObjects时执行三元操作。

1
2
3
4
5
6
7
8
9
10
11
select new MyObject
{
    field1= ga.Key.Field1,
    field2= ga.Key.Field2,
    manySubObjects =
        (from g in ga select g).FirstOrDefaut() == null ? null :
        (from g in ga select new SubObject {
           fielda= g.fielda,
           fieldb= g.fieldb
        }).ToList()
}).ToList();
  • 这里有一个dotnetfiddle试图做你想做的事情。https://dotnetfidle.net/kgjvje
  • 下面是基于您的评论的后续dotnettle。https://dotnetfidle.net/h2xd9o

作为对您的评论的回应,上面的内容适用于linq-to对象,但不适用于linq-to-sql。linq-to-sql会抱怨它,"无法翻译表达式…"这是因为Linq无法将自定义的new SubObject构造函数转换为SQL。"要做到这一点,您必须编写更多的代码来支持转换为SQL。请参阅Linq to SQL查询和本文中的自定义方法。

我想我们已经充分回答了你关于左连接的原始问题。考虑问一个关于在LinqToSQL查询中使用自定义方法/构造函数的新问题。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var results =
(
    // Use from, from like so for the left join:
    from a in dc.Table1
    from e in dc.Table2
        // Join condition goes here
        .Where(a.Id == e.Id)
        // This is for the left join
        .DefaultIfEmpty()
    // Non-join conditions here
    where a.Id == id
    // Then group
    group by new
    {
        a.Field1,
        a.Field2
    }
).Select(g =>
    // Sort items within groups
    g.OrderBy(item => item.sortField)
    // Project required data only from each item
    .Select(item => new
    {
        item.FieldA,
        item.FieldB
    }))
// Bring into memory
.ToList();

然后在内存中投影到非EF模型类型。