Simplify many LINQ Join

Kevin Burton

I have a rather complex LINQ query but that is the point of the question

var result = await _context.TblBreakpoints
            .GroupBy(b => new { b.BpgroupId, b.ResultType, b.DrugId, b.Susceptible, b.LowIntermediate, b.Intermediate, b.Resistant})
            .Join(_context.TblBreakpointgroups,
                 bg => bg.Key.BpgroupId,
                 g => g.BpgroupId,
                 (bg, g) => new
                 {
                     GroupId = bg.Key.BpgroupId,
                     DrugId = bg.Key.DrugId,
                     Susceptible = bg.Key.Susceptible,
                     LowIntermediate = bg.Key.LowIntermediate,
                     Intermediate = bg.Key.Intermediate,
                     Method = bg.Key.ResultType,
                     Resistant = bg.Key.Resistant,
                     StandardId = g.BpstandardId,
                     GroupName = g.BpgroupName,
                     Count = bg.Count(),
                 })
           .Join(_context.TblBreakpointStandards,
                i => i.StandardId,
                j => j.BpstandardId,
                (i, j) => new
                {
                    Standard = j.Bpstandard,
                    GroupId = i.GroupId,
                    GroupName = i.GroupName,
                    Count = i.Count,
                    Method = i.Method,
                    DrugId = i.DrugId,
                    Susceptible = i.Susceptible,
                    LowIntermediate = i.LowIntermediate,
                    Intermediate = i.Intermediate,
                    Resistant = i.Resistant
                })
            .Join(_context.TblDrugs,
                i => i.DrugId,
                j => j.DrugId,
                (i, j) => new
                {
                    DrugName = j.DrugName,
                    Standard = i.Standard,
                    GroupId = i.GroupId,
                    GroupName = i.GroupName,
                    Count = i.Count,
                    Method = i.Method,
                    Susceptible = i.Susceptible,
                    LowIntermediate = i.LowIntermediate,
                    Intermediate = i.Intermediate,
                    Resistant = i.Resistant
                })
           .Join(_context.TblBreakpointgroupmembers,
                 i => i.GroupId,
                 j => j.BpgroupId,
                (i, j) => new
                {
                    OrganismId = j.OrganismId,
                    Standard = i.Standard,
                    GroupId = i.GroupId,
                    GroupName = i.GroupName,
                    Count = i.Count,
                    Method = i.Method,
                    DrugName = i.DrugName,
                    Susceptible = i.Susceptible,
                    LowIntermediate = i.LowIntermediate,
                    Intermediate = i.Intermediate,
                    Resistant = i.Resistant
                })
           .Join(_context.TblOrganismNames,
                 i => i.OrganismId,
                 j => j.OrganismId,
                 (i, j) => new BreakpointSummary
                 {
                     OrganismName = j.OrganismName,
                     Standard = i.Standard,
                     GroupName = i.GroupName,
                     Count = i.Count,
                     Method = i.Method,
                     DrugName = i.DrugName,
                     Susceptible = i.Susceptible,
                     LowIntermediate = i.LowIntermediate,
                     Intermediate = i.Intermediate,
                     Resistant = i.Resistant
                 })
           .ToListAsync().ConfigureAwait(false);

From the query with each Join I keep passing the previous values and add the value(s) that come from the join. It is already tedious with just 5 joins, it would get even more so with more joins. Is there a better way that I am missing?

I think the equivalent SQL is

WITH bpg (BPGroupId, ResultType, DrugId, Susceptible, LowIntermediate, Intermediate, Resistant, Count)
AS (
SELECT BPGroupId, ResultType, DrugId, Susceptible, LowIntermediate, Intermediate, Resistant, COUNT(BPGroupId)
FROM dbo.tbl_Breakpoint a
GROUP BY BPGroupId,
         ResultType,
         DrugId,
         Susceptible,
         LowIntermediate,
         Intermediate,
         Resistant
)
SELECT a.BpgroupName, b.BPStandard, c.DrugName, e.OrganismName, CTE.ResultType, CTE.Susceptible, CTE.LowIntermediate, CTE.Intermediate, CTE.Resistant, CTE.Count
FROM dbo.tbl_breakpointgroup a
INNER JOIN bpg CTE ON a.BPGroupId = CTE.BPGroupId
INNER JOIN tbl_BreakpointStandard b ON b.BPStandardId = a.BPStandardId
INNER JOIN tbl_Drug c ON c.DrugID = CTE.DrugId
INNER JOIN tbl_breakpointgroupmember d ON d.BPGroupId = CTE.BPGroupId
INNER JOIN tbl_OrganismName e ON e.OrganismId = d.OrganismId
WHERE a.BPGroupId = CTE.BPGroupId
Ivan Stoev

In general when using manual joins in LINQ, it's better to use the query syntax since it provides range variables (which correspond to table/query aliases in SQL) transparency. e.g. (in pseudo code)

from a in queryA
join b in queryB on ... // can use any field from a
join c in queryC on ... // can use any field from a and b
join d in queryD on ... // can use any field from a, b and c
...
select new
{
    // can use any field for a, b, c, d etc.
}

The same with method syntax is a bit more complicated, but the principle is to wrap the previous "variables" in simple tuple like anonymous types until you get to the final projection, e.g. (in pseudo code)

queryA
    .Join(queryB, a => {a fields}, b => {b fields), (a, b) => new { a, b }) // first result
    .Join(queryC, r => {r.a, r.b fields), c => { c fields }, (r, c) => new { r.a, r.b, c } // second result
    .Join(queryD, r => {r.a, r.b, r.c fields), d => { d fields }, (r, d) => new { r.a, r.b, r.c, d } // third result
    ...
    .Select(r => new { r.a, r.b, r.c, r.d... fields });

Applying it to your example, the corresponding query syntax could be like (note that sub queries inside can use whatever syntax is appropriate):

var query =
    from cte in _context.TblBreakpoints
        .GroupBy(b => new { b.BpgroupId, b.ResultType, b.DrugId, b.Susceptible, b.LowIntermediate, b.Intermediate, b.Resistant})
        .Select(g => new
         { 
             g.Key.BpgroupId, g.Key.ResultType, g.Key.DrugId, g.Key.Susceptible, h.Key.LowIntermediate, g.Key.Intermediate, g.Key.Resistant,
             Count = g.Count(),
         })
    join a in _context.TblBreakpointgroups on cte.BpgroupId equals a.BpgroupId
    join b in _context.TblBreakpointStandards on a.BpstandardId equals b.BpstandardId
    join c in _context.TblDrugs on cte.DrugId equals c.DrugId
    join d in _context.TblBreakpointgroupmembers on cte.BpgroupId equals d.BpgroupId
    join e in _context.TblOrganismNames on d.OrganismId equals e.OrganismId 
    select new BreakpointSummary
    {
        OrganismName = f.OrganismName,
        Standard = b.Bpstandard,
        GroupName = a.BpgroupName,
        Count = cte.Count,
        Method = cte.ResultType,
        DrugName = d.DrugName,
        Susceptible = cte.Susceptible,
        LowIntermediate = cte.LowIntermediate,
        Intermediate = cte.Intermediate,
        Resistant = cte.Resistant,
    };

You can convert it to method syntax using the aforementioned rules, but for me it doesn't worth the effort.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Simplify many LINQ Join

From Dev

Is there a way to simplify a Linq query with a many to one relationship?

From Dev

Is there a way to simplify a Linq query with a many to one relationship?

From Dev

Simplify process with linq query

From Dev

Is it possible to simplify this LINQ statement

From Dev

Linq to Sql One to many relationship string.join

From Dev

How to simplify the code Using LINQ

From Dev

Simplify linq expression that orders children

From Dev

Linq Many to Many query

From Dev

Linq many to many include

From Dev

Linq Many to Many query

From Dev

How can I get a SingleOrDefault value from a one to many join with LINQ?

From Dev

Simplify code by finding a way to remove many if statements

From Dev

simplify freeing many pointers using macro

From Dev

Simplify code by finding a way to remove many if statements

From Dev

SQL simplify table of many columns into less column

From Dev

How can I simplify too many AND/OR in ruby

From Dev

How to simplify the multiple foreach using linq

From Dev

Many to Many relation with join table

From Dev

Many to many join Php/mysql

From Dev

How to join many to many in createQuery()

From Dev

Doctrine many to many left join

From Dev

SqlAlchemy - Many to Many outer join with conditions on join

From Dev

SqlAlchemy - Many to Many outer join with conditions on join

From Dev

Many to Many database query with LINQ

From Dev

LINQ lambda for many to many relationship

From Dev

Many to many relationships - Sql To Linq

From Dev

LINQ lambda for many to many relationship

From Dev

Linq left join with group join