C#使用左右连接创建3个表的lambda表达式

Posted

技术标签:

【中文标题】C#使用左右连接创建3个表的lambda表达式【英文标题】:C# Create lambda expression with Left and right Join with 3 tables 【发布时间】:2021-09-16 09:28:37 【问题描述】:

我目前正在为我的应用程序开发一个搜索过滤器,但我在按特定键进行过滤时遇到问题,当我制作 lambda 表达式时,它会为我提供范围内的所有值,但我不知道我还需要什么添加以正确获取过滤器。

我有三个带有各自外键的表: 表 A:id_contract, 表 B:id_build 和 id_contract, 表 C:id_build

实体如下: 表A

    public partial class TableA
    
        public TableA()
        
            this.TableB = new List<TableB>();
        
        public int id_contract  get; set;  //Primary Key
        public int id_client  get; set;  //FK another table not important for now
        public int contract_name  get; set;  //Information
   

表 B

    public partial class TableB
    
        public int id_tableB  get; set;  //primary key (not use)
        public int id_contract  get; set;  //FK Table A
        public int id_build  get; set;  //FK Table C
            
        public virtual TableC TableC  get; set; 
        public virtual TableA TableA  get; set; 
        
    

表 C

public partial class TableC
    
        public TableC()
        
            this.TableB = new List<TableB>();
        
        public int id_build  get; set;  //Primary Key
        public string build_code  get; set; 
        public virtual List<TableB> TableB  get; set; 
    

过滤器的参数来自控制器内部的 id_builds 列表,然后我使用 Contains 检查表是否具有相应的值。

我的SQL查询如下:


    SELECT c.contract_name, b.build_value, MAX(p.update_date) AS [updt_date] 
    FROM
    (
        SELECT id_contract, MAX(id_build) AS id_build
     FROM [Table B]
        GROUP BY id_contract
    ) d
    JOIN [Table B] P ON p.id_contract = d.id_contract AND p.id_build = d.id_build
    RIGHT JOIN [Table A] c WITH(NOLOCK) ON p.id_contract = c.id_contract
    LEFT JOIN [Table C] b WITH(NOLOCK) ON p.id_build = b.id_build
    /*This where is where i filter it, and the correct value must be based from id_build as below, i commented it to test and get all values from query before.*/
    WHERE c.contract_name <> 0 AND c.id_company = 1 AND c.ativo = 1 --and b.id_build = XXX 
    GROUP BY c.contract_name, b.build_value

当我在不按 XXX 值过滤的情况下运行此查询时,我会得到所有 750 个结果,这适用于任何值,并且使用过滤器,我会通过 id_build 获得 61 个结果,这些结果对应于我从过滤器中给出的任何值。

我目前在 C# 中的 lambda 表达式如下:


    results = db.TableA
           .Join(db.TableB, tbA => id_contract, tbB => id_contract, (tbA , tbB ) => new  tbA, Key = tbB.id_build)
           .Join(db.TableC, tbC => tbC.Key, FKTableB=> TableB.id_build, (tbC , FKTableB) => new tbC, FKTableB)
           .Where(c => c.tbC.tbA.ativo == true && c.tbC.tbA.id_company == 1 && id_build.Contains(c.FKTableB.id_build))
    /*ignore this select inside content, but consider it as i need this output to be printed out.*/
           .Select(x => new
                   
                      x.tbC.tbA.id_contract,
                      contract_name = x.tbC.tbA.contrato + " - " + 
                      x.tbC.tbA.client_name
                    ).ToList();

我不知道如何在这种状态下复制 Join。

谢谢!

【问题讨论】:

你能展示实体类吗? (表A、表B、表C) 您好@vernou,已添加实体。 为什么在可以使用导航属性(A.TableB 等)的同时加入 LINQ 查询?使查询更容易。 LINQ 查询可以是db.TableA.Where(...),无需任何连接。 【参考方案1】:

我不知道你到底想要什么,但我用 lambda 表达式实现了你确切的 sql 查询。

请使用以下类进行查询。我将update_date 添加到TableB 类和build_valueTableC 类。和id_companyativoTableA 类。

public partial class TableA

   public TableA()
   
       this.TableB = new List<TableB>();
   
   public int id_contract  get; set;  //Primary Key
   public int id_client  get; set;  //FK another table not important for now
   public int contract_name  get; set;  //Information
   public int id_company  get; set;  //Information
   public int ativo  get; set; 
   public virtual List<TableB> TableB  get; set; 

public partial class TableB

   public int id_tableB  get; set;  //primary key (not use)
   public int id_contract  get; set;  //FK Table A
   public int id_build  get; set;  //FK Table C
   public DateTime update_date  get; set; 
   public virtual TableC TableC  get; set; 
   public virtual TableA TableA  get; set; 


public partial class TableC

   public TableC()
   
      this.TableB = new List<TableB>();
   
   public int id_build  get; set;  //Primary Key
   public string build_code  get; set; 
   public int build_value  get; set; 
   public virtual List<TableB> TableB  get; set; 

lambda 表达式

var results = db.TableB
     .GroupBy(a => a.id_contract)
     .Select(a => new
     
        id_contract = a.Key,
        id_build = a.Max(x => x.id_build)
     )
     .Join(db.TableB,
        a => new  a.id_contract, a.id_build ,
        b => new  b.id_contract, b.id_build ,
        (a, b) => new  id_contract = a.id_contract, id_build = a.id_build, tB = b 
     )
     .Join(db.TableA,
        a => a.id_contract,
        b => b.id_contract,
        (a, b) => new  id_contract = a.id_contract, id_build = a.id_build, tB = a.tB, tA = b 
     )
     .Join(db.TableC,
        a => a.id_build,
        b => b.id_build,
       (a, b) => new  id_contract = a.id_contract, id_build = a.id_build, tB = a.tB, tA = a.tA, tC = b )
     .Where(a=>a.tA.contract_name != 0 && a.tA.id_company == 1 && a.tA.ativo == 1)
     .GroupBy(a => new  a.tA.contract_name, a.tC.build_value )
     .Select(a => new
      
         contract_name = a.Key.contract_name,
         build_value = a.Key.build_value,
         updt_date = a.Max(x => x.tB.update_date)
      ).ToList();

【讨论】:

非常感谢,它帮助我了解了我遗漏的地方,我的目标是调整该查询以充当基于表 C 中的 id_build 的过滤器,现在它可以工作了!

以上是关于C#使用左右连接创建3个表的lambda表达式的主要内容,如果未能解决你的问题,请参考以下文章

Java学习笔记3.9.1 Lambda表达式 - Lambda表达式入门

Java Lambda 表达式的官网教程理解

C# MySQL 连接 3 个表

mysql中3个表的内连接

用于 4 个表的 SQL Server 2008 连接类型

EF linq/lambdas 使用 concat 连接 2 个表