Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

double inner join in linq/ lambda query?

i got this SQL -query that i want converted to Linq. this is the contect:

im making a asp.net api that needs to return values from 3 different tables

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,

I left out all the foreignkeys and primary. This is just for the clarification of what i want. My problem is now that i have a function that needs to return information from several tables. The sql query looks like this=

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;

i get all the "verenigingen"from lidid=1 and show all of information the "verenigingen"have in the table Location.

But when i try to do this using linq/lambda it goes wrong; my function looks like this:

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
    }

}

my verenigingmodel looks like this:

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; }
}

my library context looks like this:

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; }
}

what im trying to achieve is that i put all of the different information in the verenigingmodel and from there on put it as output out of my rest api:

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

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

        return new JsonResult(verenigingFromRepo);

    }
like image 949
louisschrauwen Avatar asked May 11 '17 11:05

louisschrauwen


2 Answers

I would do the function a bit diffrent. Like this:

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

I personally find it easier to see the joins like this and combine the result into a object

like image 92
Arion Avatar answered Oct 21 '22 04:10

Arion


To implement behaviour equal to sql query, you should modify your code as following:

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

or use inline linq methods, as Arion suggested. His version is more readable, my version for those who really like lambdas, anonymous types and so on.

like image 38
Mikhail Tulubaev Avatar answered Oct 21 '22 03:10

Mikhail Tulubaev