SQL左外部联接中具有多个条件的C#Lambda联接
我有以下SQL:SQL左外部联接中具有多个条件的C#Lambda联接,c#,lambda,left-join,C#,Lambda,Left Join,我有以下SQL: select * from [dbo].[CustomField] cf left outer join [dbo].[CustomFieldDataItem] cd on cd.CustomFieldId = cf.Id and cd.OutsideId = 180 where cf.AnotherId = 1 我想用C#Lambda编写它,但我的代码只显示有数据项的自定义字段的数据项-我想查看所有自定义字段以及它们是否有数据项-到目前为止,我得到了以下信
select *
from [dbo].[CustomField] cf
left outer join [dbo].[CustomFieldDataItem] cd on cd.CustomFieldId = cf.Id and cd.OutsideId = 180
where cf.AnotherId = 1
我想用C#Lambda编写它,但我的代码只显示有数据项的自定义字段的数据项-我想查看所有自定义字段以及它们是否有数据项-到目前为止,我得到了以下信息:
var myQuery = _db.CustomFields
.Where(c => c.AnotherId == 1)
.Join(_db.CustomFieldDataItems, cf => cf.Id, cd => cd.CustomFieldId, (cf, cd) => new { cf, cd })
.Where(f => f.cd.OutsideId == 180)
.Select(z => new CustomFieldModel
{
CustomFieldId = z.cf.Id,
Name = z.cf.Name,
DataValue = z.cd.DataValue
}).ToList()
我不知道在哪里放置outsided where子句,它实际上应该是join的一部分
在Linq中,您很少需要加入:
var myQuery = _db.CustomFields
.Where(c => c.AnotherId == 1)
.Select(cf => new CustomFieldModel
{
CustomFieldId = cf.Id,
Name = cf.Name,
DataValue = cf.cd.Any(cd => cd.OutSideId == 180)
? cf.cd.First(cd => cd.OutSideId == 180).DataValue
: (<type?>)null;
}).ToList();
这实际上不会用原始SQL生成结果(我首先使用DataValue,这意味着您不会得到1-Many的结果)
然后,我们可以在这个优化版本中重写它,它也会生成您原来的结果(不确定您是否希望重复CustomFields中的行-您的SQL会):
编辑:进一步考虑,可以简化为:
var myQuery = (from cf in CustomFields
from cd in cf.CustomFieldDataItems.Where(d => d.OutsideId==180).DefaultIfEmpty()
where cf.AnotherId == 1
select new CustomFieldModel
{
CustomFieldId = cf.Id,
Name = cf.Name,
DataValue = (int?)cd.DataValue,
AnotherValue = (<typeName?>)cd.AnotherValue,
}).ToList();
和你原来的差不多
仅用于填写“lambda”:
var myQuery=\u db.CustomFields
.其中(cf=>cf.AnotherId==1)
.SelectMany(
cf=>cf.CustomFieldDataItems.Where(cd=>(cd.OutsideId==(Int32?)180)).DefaultIfEmpty(),
(cf,cd)=>新的CustomFieldModel
{
CustomFieldId=cf.Id,
名称=参照名称,
DataValue=(int?)cd.DataValue,
AnotherValue=()cd.AnotherValue,
}
).ToList();
如果你有导航属性,你可以这样做:
var myQuery = _db.CustomFields.Include(x => x.CustomFieldDataItems && x.CustomFieldDataItems.OutsideId == 180)
.Where(c => c.AnotherId == 1).Select(z => new CustomFieldModel
{
CustomFieldId = z.Id,
Name = z.Name,
DataValue = z.CustomFieldDataItems.DataValue
}).ToList()
“Include”是数据库t上的“左外部联接”
编辑:更改包含lambda为了响应所有@Cetin Basoz工作,我能够在lambda中使用LinqPad获得解决方案-在本例中,我需要使用SelecctMany()而不是Join:
var myQuery = _db.CustomFields.SelectMany(
cf => cf.DataItems.Where(d => d.OutsideId == x.Id).DefaultIfEmpty(),
(cf, cd) => new {cf, cd })
.Where(s => s.cf.AnotherId == 1)
.Select(
m =>
new MyModel
{
CustomFieldId = m.cf.Id,
Name = m.cf.Name,
DataType = m.cf.DataType,
StringValue = m.cd.StringValue,
IntValue = m.cd.IntValue,
BoolValue = m.cd.BoolValue,
DateTimeValue = m.cd.DateTimeValue,
DecimalValue = m.cd.DecimalValue
}
).ToList()
实体CustomFields对实体CustomFieldDataItems具有导航属性?是的CustomFieldId这没有任何区别此查询是一个更大的查询的一部分-我返回的列多于数据项的数据值-因此,如果我遵循您的建议,我将每天多次查询数据项表一行效率在这里很重要-这就是为什么我需要lambdajoin@MrRich,事实并非如此。虽然这与您的查询不是1:1匹配,但它是类似的,可以进行优化。我将编辑我的答案,添加一些解释和优化。@Rich先生,我希望“lambda”不是必须的,否则你可以使用SelectMany来实现它,但不值得。我确实需要lambda和SelectMany解决了它-因为你的LINQ示例,我能够使用LINQPAD翻译它-它使用select自动翻译它many@MrRich,我不明白为什么您“确实需要”lambda,但无论如何,这将转换为SelectMany到lambda:)顺便说一句,我利用LinqPad获得生成的SQL。不,这不起作用,因为outsideid=180会过滤掉没有数据项的行。我需要复制SQL,它在join中有两个条件,我觉得不合适。检查我在邮件末尾添加的lambda版本。对于“左连接”,这样写而不使用null值很可能会出错。
DECLARE @p0 Int = 1;
DECLARE @p1 Int = 180;
SELECT [t0].[CustomFieldId], [t0].[Name],
(CASE
WHEN [t2].[test] IS NULL THEN NULL
ELSE [t2].[DataValue]
END) AS [DataValue],
(CASE
WHEN [t2].[test] IS NULL THEN NULL
ELSE [t2].[AnotherValue]
END) AS [AnotherValue]
FROM [CustomFields] AS [t0]
LEFT OUTER JOIN (
SELECT 1 AS [test], [t1].[DataValue], [t1].[CustomFieldID], [t1].[AnotherValue], [t1].[OutsideId]
FROM [CustomFieldDataItems] AS [t1]
) AS [t2] ON ([t2].[OutsideId] = @p0) AND ([t2].[CustomFieldID] = [t0].[ID])
WHERE [t0].[AnotherId] = @p1;
var myQuery = (from cf in CustomFields
from cd in cf.CustomFieldDataItems.Where(d => d.OutsideId==180).DefaultIfEmpty()
where cf.AnotherId == 1
select new CustomFieldModel
{
CustomFieldId = cf.Id,
Name = cf.Name,
DataValue = (int?)cd.DataValue,
AnotherValue = (<typeName?>)cd.AnotherValue,
}).ToList();
DECLARE @p0 Int = 180;
DECLARE @p1 Int = 1;
SELECT [t0].[CustomFieldId], [t0].[Name],
[t1].[DataValue], [t1].[AnotherValue]
FROM [CustomFields] AS [t0]
LEFT OUTER JOIN [CustomFieldDataItems] AS [t1]
ON ([t1].[OutSideId] = @p0) AND ([t1].[CustomFieldID] = [t0].[ID])
WHERE [t0].[AnotherId] = @p1;
var myQuery = _db.CustomFields
.Where (cf => cf.AnotherId == 1)
.SelectMany (
cf => cf.CustomFieldDataItems.Where (cd => (cd.OutsideId == (Int32?)180)).DefaultIfEmpty(),
(cf, cd) => new CustomFieldModel
{
CustomFieldId = cf.Id,
Name = cf.Name,
DataValue = (int?)cd.DataValue,
AnotherValue = (<typeName?>)cd.AnotherValue,
}
).ToList();
var myQuery = _db.CustomFields.Include(x => x.CustomFieldDataItems && x.CustomFieldDataItems.OutsideId == 180)
.Where(c => c.AnotherId == 1).Select(z => new CustomFieldModel
{
CustomFieldId = z.Id,
Name = z.Name,
DataValue = z.CustomFieldDataItems.DataValue
}).ToList()
var myQuery = _db.CustomFields.SelectMany(
cf => cf.DataItems.Where(d => d.OutsideId == x.Id).DefaultIfEmpty(),
(cf, cd) => new {cf, cd })
.Where(s => s.cf.AnotherId == 1)
.Select(
m =>
new MyModel
{
CustomFieldId = m.cf.Id,
Name = m.cf.Name,
DataType = m.cf.DataType,
StringValue = m.cd.StringValue,
IntValue = m.cd.IntValue,
BoolValue = m.cd.BoolValue,
DateTimeValue = m.cd.DateTimeValue,
DecimalValue = m.cd.DecimalValue
}
).ToList()