左加入 Linq 查询
left join in Linq query
我试图在 linq 查询中进行左连接,而不是内部连接。我找到了与使用 DefaultIfEmpty()
相关的答案,但我似乎无法让它发挥作用。以下是 linq 查询:
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();
查询只给我 table 1 中的行,这些行在 table 2 中有相应的记录。我希望 table 1 中的每条记录都填充到 MyObject 和一个列表中每个 MyObject 的 manySubObjects 中列出的 0-n 个对应记录。
更新:
我尝试了下面提到的 "possible duplicate" 问题的答案。我现在有以下代码,即使没有 Table2 记录,它确实为 Table1 中的每个项目提供了一条记录。
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();
但是,使用此代码,当 table2 中没有记录时,我得到 "manySubObject" 作为一个列表,其中有一个 "SubObject",其中的属性的所有值为空"SubObject"。如果 table2.
中没有值,我真正想要的是 "manySubObjects" 为 null
回复您的更新,要创建空列表,您可以在 manySubObjects
的分配中进行三元运算。
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://dotnetfiddle.net/kGJVjE
- 这是基于您的评论的后续 dotnetfiddle。 https://dotnetfiddle.net/h2xd9O
回复您的评论,以上内容适用于 Linq to Objects 但不适用于 Linq to SQL。 Linq to SQL 会抱怨它,"Could not translate expression ... into SQL and could not treat as a local expression." 那是因为 Linq 无法将自定义 new SubObject
构造函数转换为 SQL。为此,您必须编写更多代码来支持翻译成 SQL。参见 Custom Method in LINQ to SQL query and this article。
我认为我们已经充分回答了您最初关于左联接的问题。考虑问一个关于在 Linq to SQL 查询中使用自定义 methods/constructors 的新问题。
我想你想要的结果可以通过GroupJoin()
得到
下面的代码将产生这样的结构
字段 1、字段 2、列表 <子对象> 如果为空则为 null
示例代码
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();
Dotnetfiddle link
更新
从你的评论中我看到了这个
ga.Select(g = > new SubObject(){fielda = g.fielda, fieldb = g.fieldb})
我认为应该是(取决于 "ga" 是如何构建的)
ga.Select(g => new SubObject {fielda = g.fielda, fieldb = g.fieldb})
请用整个查询更新您的问题,这将有助于解决问题。
** 更新 BIS **
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()
应该是:
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()
检查组是否有 First,如果没有,则组没有任何记录,因此时间戳的 Action.Name 没有要发送的电子邮件。如果第一个不为空,则循环抛出组元素并创建一个电子邮件列表,
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 模型类型。
我试图在 linq 查询中进行左连接,而不是内部连接。我找到了与使用 DefaultIfEmpty()
相关的答案,但我似乎无法让它发挥作用。以下是 linq 查询:
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();
查询只给我 table 1 中的行,这些行在 table 2 中有相应的记录。我希望 table 1 中的每条记录都填充到 MyObject 和一个列表中每个 MyObject 的 manySubObjects 中列出的 0-n 个对应记录。
更新: 我尝试了下面提到的 "possible duplicate" 问题的答案。我现在有以下代码,即使没有 Table2 记录,它确实为 Table1 中的每个项目提供了一条记录。
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();
但是,使用此代码,当 table2 中没有记录时,我得到 "manySubObject" 作为一个列表,其中有一个 "SubObject",其中的属性的所有值为空"SubObject"。如果 table2.
中没有值,我真正想要的是 "manySubObjects" 为 null回复您的更新,要创建空列表,您可以在 manySubObjects
的分配中进行三元运算。
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://dotnetfiddle.net/kGJVjE
- 这是基于您的评论的后续 dotnetfiddle。 https://dotnetfiddle.net/h2xd9O
回复您的评论,以上内容适用于 Linq to Objects 但不适用于 Linq to SQL。 Linq to SQL 会抱怨它,"Could not translate expression ... into SQL and could not treat as a local expression." 那是因为 Linq 无法将自定义 new SubObject
构造函数转换为 SQL。为此,您必须编写更多代码来支持翻译成 SQL。参见 Custom Method in LINQ to SQL query and this article。
我认为我们已经充分回答了您最初关于左联接的问题。考虑问一个关于在 Linq to SQL 查询中使用自定义 methods/constructors 的新问题。
我想你想要的结果可以通过GroupJoin()
得到下面的代码将产生这样的结构
字段 1、字段 2、列表 <子对象> 如果为空则为 null
示例代码
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();
Dotnetfiddle link
更新
从你的评论中我看到了这个
ga.Select(g = > new SubObject(){fielda = g.fielda, fieldb = g.fieldb})
我认为应该是(取决于 "ga" 是如何构建的)
ga.Select(g => new SubObject {fielda = g.fielda, fieldb = g.fieldb})
请用整个查询更新您的问题,这将有助于解决问题。
** 更新 BIS **
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()
应该是:
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()
检查组是否有 First,如果没有,则组没有任何记录,因此时间戳的 Action.Name 没有要发送的电子邮件。如果第一个不为空,则循环抛出组元素并创建一个电子邮件列表,
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 模型类型。