SQL左外部联接中具有多个条件的C#Lambda联接

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编写它,但我的代码只显示有数据项的自定义字段的数据项-我想查看所有自定义字段以及它们是否有数据项-到目前为止,我得到了以下信

我有以下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编写它,但我的代码只显示有数据项的自定义字段的数据项-我想查看所有自定义字段以及它们是否有数据项-到目前为止,我得到了以下信息:

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()