How To Join Many Tables In Linq Lambda Expressions? - c#

I Got This Lambda Expression But Does Not Work Correctly.Does Not Return Any Thing.Would You Help me Please on this:
var query = db.Cheque
.Join(db.Contracts,
C => C.ContractIDRef,
Con => Con.ContractID,
(C, Con) => new { Cheques1 = C, Contracts1 = Con })
.Join(db.Parties,
Con => Con.Contracts1.ContractID,
Pt => Pt.ContractIDRef,
(Con, Pt) => new { Contract2 = Con, Parites1 = Pt })
.Join(db.Persons,
Pt => Pt.Parites1.PartyIDRef,
P => P.PersonID,
(Pt, P) => new { Parites2 = Pt, Persons1 = P })
.Join(db.Company,
Pt => Pt.Parites2.Parites1.CompanyIDRef,
Com => Com.CompanyID,
(Pt, Com) => new { Parites3 = Pt, Company1 = Com })
.Join(db.Bank,
C => C.Parites3.Parites2.Contract2.Cheques1.BankIDRef,
B => B.BankID,
(C, B) => new { Cheque2 = C, Bank1 = B })
.Join(db.Flats,
Con => Con.Cheque2.Parites3.Parites2.Contract2.Contracts1.FlatIDRef,
F => F.FlatID,
(Con, F) => new { Contract3 = Con, Flat1 = F })
.Join(db.Projects,
F => F.Flat1.ProjectIDRef,
Pr => Pr.ProjectID,
(F, Pr) =>
new
{
ChequeNumber = F.Contract3.Cheque2.Parites3.Parites2.Contract2.Cheques1.ChequeNo,
ChequeIDRef = F.Contract3.Cheque2.Parites3.Parites2.Contract2.Cheques1.ChequeIDRef,
ChequePrice = F.Contract3.Cheque2.Parites3.Parites2.Contract2.Cheques1.Amount,
BankName = F.Contract3.Bank1.BankName,
BranchName = F.Contract3.Cheque2.Parites3.Parites2.Contract2.Cheques1.BranchName,
ChequeDate = F.Contract3.Cheque2.Parites3.Parites2.Contract2.Cheques1.ChequeDate,
AccountNumber = F.Contract3.Cheque2.Parites3.Parites2.Contract2.Cheques1.AccNo,
AccountOwner = F.Contract3.Cheque2.Parites3.Parites2.Contract2.Cheques1.ChequeOwnerName,
}
)
`.Where(Total => SelectedChequesList.Contains(Total.ChequeIDRef.Value)).ToList();

I will start with converting the above to the query syntax. While I'm a fan of the method syntax, using it in a complex queries involving multiple joins is a real pain. I needed a lot of time to read and try to follow the above query, so let do that:
var query =
from cheque in db.Cheque
join contract in db.Contracts on cheque.ContractIDRef equals contract.ContractID
join party in db.Parties on contract.ContractID equals party.ContractIDRef
join person in db.Persons on party.PartyIDRef equals person.PersonID
join company in db.Companies on party.CompanyIDRef equals company.CompanyID
join bank in db.Bank on cheque.BankIDRef equals bank.BankID
join flat in db.Flats on contract.FlatIDRef equals flat.FlatID
join project in db.Projects on flat.ProjectIDRef equals project.ProjectID
where SelectedChequesList.Contains(cheque.ChequeIDRef.Value)
select new
{
ChequeNumber = cheque.ChequeNo,
ChequeIDRef = cheque.ChequeIDRef,
ChequePrice = cheque.Amount,
BankName = bank.BankName,
BranchName = cheque.BranchName,
ChequeDate = cheque.ChequeDate,
AccountNumber = cheque.AccNo,
AccountOwner = cheque.ChequeOwnerName,
};
Now, one thing that can be seen is that most of the joins are not used. But let assume they are needed for some reason. Note that all the joins are INNER joins, so any of them can cause the query to return empty result if there is no matching record.
The problem is most probably in this join
join person in db.Persons on party.PartyIDRef equals person.PersonID
Instead of PartyIDRef I guess it should be something like PersonIDRef.

Related

Simplify many LINQ Join

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
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 = e.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.

Can't find the foreign key using Join for method syntax

I have these two tables: Category (Parent) and Product (Children).
I could use inner join with LINQ query syntax. But with method syntax, I could not get. p. doesn't load CategoryID
var db = new NorthwindEntities();
var cats = db.Categories;
var prods = db.Products;
var catProducts1 = from c in db.Categories
join p in db.Products
on c.CategoryID equals p.CategoryID
select new { c.CategoryName, p.ProductName };
var catProducts2 = db.Categories
.Join(db.Products, c=>c.CategoryID,p=>p);
Below is the correct syntax of Join lamda syntax for your scenario:
var catProducts2 = db.Categories.Join(db.Products,
c => c.CategoryId,
p => p.CategoryID,
(c, p) => new { c.CategoryName, p.ProductName })
.Select(s => new { s.CategoryName, s.ProductName });
You can check the usage of above query at fiddle -- https://dotnetfiddle.net/C3N2I2

How to make this query with lambda expression in Entity Framework?

This is my SQL query:
select
m.Name, s.Time, t.TheaterNumber
from
Movies m
join
MovieSeanceTheaters mst on mst.MovieId = m.MovieID
join
Theaters t on t.ID = mst.TheaterId
join
Seances s on mst.SeanceId = s.ID
This is my attempt at a Linq query:
var result = (from m in _context.Movies
join mst in _context.MovieSeanceTheaters on m.ID equals mst.MovieId
join t in _context.Theaters on mst.TheaterId equals t.ID
join s in _context.Seances on mst.TheaterId equals s.ID
select new { Film = m.Name, Salon = t.Name, Seans = s.Time }
).ToList();
I made this attempt, but I want to make with lambda for instance:
var result = movieManager.GetAll().Where(x => x.MovieSeanceTheaters)....
I couldn't do that.
If I understand you correctly, you want to rewrite your query from query syntax to method syntax?
Here we are!
var result = _context.Movies
.Join(_context.MovieSeanceTheaters,
m => m.MovieID,
mst => mst.MovieID,
(m, mst) => new
{
m = m,
mst = mst
})
.Join(_context.Theaters,
temp0 => temp0.mst.TheaterID,
t => t.ID,
(temp0, t) =>
new
{
temp0 = temp0,
t = t
})
.Join(_context.Seances,
temp1 => temp1.temp0.mst.TheaterID,
s => s.ID,
(temp1, s) =>
new
{
Film = temp1.temp0.m.Name,
Salon = temp1.t.TheaterNumber,
Seans = s.Time
});
Looks ugly, doesn't it?
Most often, the method syntax is more compact and convenient. But in this case, leave it as is.

SQL query to LINQ conversion with nested select statements

I want to convert the following query to LINQ:
SELECT LV.* FROM LowerVehicles LV
INNER JOIN (Select VSerial,MAX(updatedOn) MaxUpdatedOn from LowerVehicles group by vserial) LVG
ON LV.VSerial = LVG.VSerial AND LV.updatedOn = LVG.MaxUpdatedOn
Not knowing your entities classes, here is an approximation. You can use query syntax or fluent syntax. Sometimes one is preferable over the other, and in the case of joins and grouping I prefer to use query syntax.
QUERY SYNTAX
var query = from LV in LowerVehicles
join LVG in (
from r in LowerVehicles
group r by r.vserial into g
select new {VSerial = g.Key, MaxUpdatedOn = g.Max(t => t.updatedOn)})
on LV.VSerial equals LVG.Vserial
and LV.updatedOn equals LVG.MaxUpdatedOn
select LV;
FLUENT SYNTAX
var lvg = LowerVehicles.GroupBy(t => t.vserial)
.Select(g => new {
VSerial = g.Key,
MaxUpdatedOn = g.Max(t => t.updatedOn)
});
var query = LowerVehicles.Join(
lvg,
a => new { a.VSerial, a.updatedOn },
b => new { b.VSerial, b.MaxUpdatedOn },
(a, b) => new { LV = a, LVG = b}
)
.Select(t=> t.LV);
Something like this?
Something.LowerVehicles
.Join(something.LowerVehicles.Select(y => new { y.VSerial, updatedOn = y.updatedOn.Max() }).GroupBy(z => z.VSerial),
x => new { x.VSerial, x.updatedOn },
lvg => new { lvg.VSerial, lvg.updatedOn },
(x, y) => x)

Linq outer Join

How do I change this query to an outer join so that customers with no orders still appear in the results?
Customers
.Join(
Orders,
c => c.ID,
r => r.ID,
(c, r) =>
new
{
Name = c.Name,
Address = c.Address,
OrderNumber = r.OrderNumber,
OrderDetails = r.OrderDetails
}
).ToList()
from c in context.Customers
join o in context.order on new { cid = c.cid } equals new { cid = o.cid } into ljoin
from l in ljoin.DefaultIfEmpty()
select new()
{
//whatever
};

Categories