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

时间:2019-01-11 12:56:10

标签: 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编写它,但我的代码仅显示具有数据项的自定义字段的数据项-我想查看所有自定义字段以及它们是否具有数据项-到目前为止,我已经做到了:

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

我不知道将OutsideId where子句放在哪里,该子句实际上应该是联接的一部分

4 个答案:

答案 0 :(得分:2)

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

在LinqToSQL中,这将生成类似以下的SQL:

DECLARE @p0 int = 1;
DECLARE @p1 Int = 180;
DECLARE @p2 Int = 180;

SELECT [t0].[CustomFieldId], [t0].[Name], 
    (CASE 
        WHEN EXISTS(
            SELECT NULL AS [EMPTY]
            FROM [CustomFieldDataItems] AS [t1]
            WHERE ([t1].[OutsideID] = @p1) AND ([t1].[CustomFieldID] = [t0].[ID])
            ) THEN (
            SELECT [t3].[DataValue]
            FROM (
                SELECT TOP (1) [t2].[DataValue]
                FROM [CustomFieldDataItems] AS [t2]
                WHERE ([t2].[OutsideID] = @p2) AND ([t2].[CustomFieldID] = [t0].[ID])
                ) AS [t3]
            )
        ELSE NULL
     END) AS [DataValue]
FROM [CustomFields] AS [t0]
WHERE [t0].[AnotherId] = @p0

这实际上不会在原始SQL中产生结果(我使用First来获取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 = cd == null?(int?)null:cd.DataValue,
                 AnotherValue = cd == null?(<typeName?>)null:cd.AnotherValue,
             }).ToList();

生成的SQL看起来像:

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

这将生成类似SQL的

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;

几乎与原始版本相同。

只需以“ lambda”形式填写即可:

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

答案 1 :(得分:0)

尝试.DefaultIfEmpty()

var myQuery = _db.CustomFields                   
    .Where(c => c.AnotherId == 1)
    .Join(_db.CustomFieldDataItems.DefaultIfEmpty(), 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()  

答案 2 :(得分:0)

如果您具有导航属性,则可以这样:

pandoc --columns=80 -o output.pdf ProjectDescription.md

“包含”是数据库t上的“左外连接”

编辑:已更改包含lambda

答案 3 :(得分:-1)

响应所有@Cetin Basoz的工作,我能够在Lambda中使用LinqPad获得解决方案-代替Join,在此示例中,我需要使用SelecctMany():

File file = new File("/Users/anvita.pandey/Desktop/file upload/KPSL/kpsl_n67_fatp_evt_site13.xlsx");
StringSelection stringSelection= new StringSelection(file.getAbsolutePath());

    Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null);
    Robot robot = new Robot();
    robot.keyPress(KeyEvent.VK_META);
    robot.keyPress(KeyEvent.VK_TAB);
    robot.keyRelease(KeyEvent.VK_META);
    robot.keyRelease(KeyEvent.VK_TAB);
    robot.delay(500);
    //System.out.println("changing window hanlder ");

    //driver.switchTo().window(driver.getWindowHandle());
    //Open Goto window
            robot.keyPress(KeyEvent.VK_META);
            robot.keyPress(KeyEvent.VK_SHIFT);
            robot.keyPress(KeyEvent.VK_G);
            robot.keyRelease(KeyEvent.VK_META);
            robot.keyRelease(KeyEvent.VK_SHIFT);
            robot.keyRelease(KeyEvent.VK_G);
            //Paste the clipboard value
            robot.keyPress(KeyEvent.VK_META);
            robot.keyPress(KeyEvent.VK_V);
            robot.keyRelease(KeyEvent.VK_META);
            robot.keyRelease(KeyEvent.VK_V);

            //Press Enter key to close the Goto window and Upload window


            robot.keyPress(KeyEvent.VK_ENTER);
            robot.keyRelease(KeyEvent.VK_ENTER);
            robot.delay(500);
            robot.keyPress(KeyEvent.VK_ENTER);

            robot.keyRelease(KeyEvent.VK_ENTER);