linq/lambda 查询中的双内连接?

Posted

技术标签:

【中文标题】linq/lambda 查询中的双内连接?【英文标题】:double inner join in linq/ lambda query? 【发布时间】:2017-10-10 09:50:41 【问题描述】:

我得到了想要转换为 Linq 的 SQL 查询。 这是联系方式:

我正在制作一个需要从 3 个不同表返回值的 asp.net api

CREATE TABLE Locatie (
   locatieId            INT IDENTITY(1,1)    not null,
   postcode             VARCHAR(10)          not null,
   huisnummer           INT                  not null,
   adres                VARCHAR(50)          not null,
   plaats               VARCHAR(50)          not null,




CREATE TABLE Vereniging (
   verenigingId         INT IDENTITY(1,1)    not null,
   locatieId            INT                  not null,
   naam                 VARCHAR(50)          not null,
   facebookGroupId      BIGINT               null,


CREATE TABLE Saldo (
   saldoId              INT IDENTITY(1,1)    not null,
   lidId                INT                  not null,
   verenigingId         INT                  not null,
   bedrag               SMALLMONEY           not null,

我省略了所有外键和主键。这只是为了澄清我想要的。我现在的问题是我有一个需要从多个表中返回信息的函数。 sql 查询如下所示=

Select v.verenigingId, l.postcode, l.huisnummer, l.adres,l.plaats,v.naam,v.facebookGroupId 
from Vereniging v inner join Saldo s
on v.verenigingId = s.verenigingId
inner join Locatie l
on v.locatieId=l.locatieId
where s.lidId = 1;

我从 lidid=1 得到所有“verenigingen”,并在表 Location 中显示“verenigingen”的所有信息。

但是当我尝试使用 linq/lambda 执行此操作时,它会出错; 我的函数如下所示:

public class LibraryRepository : ILibraryRepository

    private LibraryContext _context;

    public LibraryRepository(LibraryContext context)
    
        _context = context;
    

    public bool Save()
    
        return (_context.SaveChanges() >= 0);
    

    public IEnumerable<Verenigingmodel> GetVerenigingenperLid(int lidId)
    
        return _context.Vereniging
            .Join(
                _context.Saldo.Where(b => b.lidId == lidId),
            ver => ver.verenigingId,
                sal => sal.verenigingId,
                (ver, sal) => new Viewmodel  Vereniging = ver, Saldo = sal )
            .Join(
                _context.Locatie,
                verr => verr.Vereniging.locatieId,
                loca => loca.locatieId,
                (vr, loca) => new Viewmodel  Locatie = loca );
                //this returns wrong sql information
    

我的 verenigingmodel 看起来像这样:

public class Verenigingmodel

    public int verenigingId  get; set; 
    public string postcode  get; set; 
    public int huisnummer  get; set; 
    public string adres  get; set; 
    public string plaats  get; set; 
    public string naam  get; set; 
    public int facebookGroupId  get; set; 

我的库上下文如下所示:

public class LibraryContext : DbContext

    public LibraryContext(DbContextOptions<LibraryContext> options)
       : base(options)
    
        Database.Migrate();
    

    public DbSet<Gebruiker> Gebruiker  get; set; 
    public DbSet<Lid> Lid  get; set; 
    public DbSet<Vereniging> Vereniging  get; set; 
    public DbSet<Saldo> Saldo  get; set; 
    public DbSet<Locatie> Locatie  get; set; 

我想要实现的是,我将所有不同的信息放入 verenigingmodel 中,然后将其作为我的 rest api 的输出:

    [HttpGet("api/Vereniging/lidId")]

    public IActionResult FindVereniGingenPerLid(int lidId)
    
        var verenigingFromRepo = vlibraryRepository.GetVerenigingenperLid(lidId);

        return new JsonResult(verenigingFromRepo);

    

【问题讨论】:

我猜,它返回空的ViewModel,只有Locatie 填充?还是有其他问题? 【参考方案1】:

我会做的功能有点不同。像这样:

public IEnumerable<Verenigingmodel> GetVerenigingenperLid(int lidId)

    return (
        from v in _context.Vereniging
        join s in _context.Saldo
            on v.verenigingId equals s.verenigingId
        join l in _context.Locatie
            on v.locatieId equals l.locatieId
        select new Verenigingmodel()
        
            verenigingId= v.verenigingId,
            postcode=l.postcode,
            huisnummer=l.huisnummer,
            adres=l.adres,
            naam=v.naam,
            facebookGroupId=v.facebookGroupId,
            plaats=l.plaats
        
     ).ToList();

我个人觉得这样更容易看到连接并将结果组合到一个对象中

【讨论】:

感谢您的回答!这正是我需要的! @louisschrauwen 欢迎来到 ***。如果您觉得答案有用,请点赞,如果答案有助于您解决问题,请将其标记为答案(在答案总票数下方打勾)【参考方案2】:

要实现等同于 sql 查询的行为,你应该修改你的代码如下:

return _context.Vereniging
    .Join(
        _context.Saldo.Where(b => b.lidId == lidId),
        v => v.verenigingId,
        s => s.verenigingId,
        (v, s) => new  Vereniging = v, Saldo = s )
    .Join(
        _context.Locatie,
        v => v.Vereniging.locatieId,
        l => l.locatieId,
        (v, l) => 
        new Verenigingmodel 
        
            verenigingId = v.Vereniging.id,
            postcode = l.postcode,
            huisnummer = l.huisnummer,
            adres = l.adres,
            plaats = l.plaats,
            naam = v.Vereniging.naam,
            facebookGroupId = v.Vereniging.facebookGroupId
        );

或者按照 Arion 的建议使用内联 linq 方法。他的版本更具可读性,我的版本是为那些真正喜欢 lambdas、匿名类型等的人准备的。

【讨论】:

以上是关于linq/lambda 查询中的双内连接?的主要内容,如果未能解决你的问题,请参考以下文章

(Linq/Lambda) 使用 2 个 DBContext 连接 2 个或更多表

内部在LINQ Lambda中使用两个相等的内部连接

如何使用 linq lambda 扩展方法执行带有 where 子句的左外连接

Linq.join_lambda知识点

LINQ Lambda 连接错误 - 无法从使用中推断

寻找两个表/查询之间的双左连接的改进