I have an SQL Query to do with Lambda Expressions like this, generally with more joins than in this example.
select Table2.a,
Table2.b,
Table2.c,
Table2.d
from Table1
LEFT OUTER JOIN Table2
ON Table2.a = Table1.a and
Table2.b = Table1.b and
Table2.c = Table1.c
LEFT OUTER JOIN Table3
ON Table3.b = Table1.b AND
Table3.c = Table1.c AND
Table3.d = Table1.d
where ( Table1.a = ValueA )
order by Table3.f
I'm doing this with Join() Lambda Expression, but i see in SQL Server profiler that this generate an INNER JOIN and i need a LEFT OUTER JOIN.
This is how i'm doing it with Join()
var RS = DBContext.Table1.Join(DBContext.Table2,
Table1 => new {Table1.a, Table1.b, Table1.c},
Table2 => new {Table1.a, Table1.b, Table1.c},
(Table1, Table2) => new {Table1})
.Join(DBContext.Table3,
LastJoin => new {LastJoin.Table1.b, LastJoin.Table1.c, LastJoin.Table1.d},
Table3 => new {Table3.b, Table3.c, Table3.d},
(LastJoin,Table3) => new {LastJoin.Table1, Table3})
.Where (LastTable => LastTable.Table1.a == ValueA)
.OrderBy(LastTable => LastTable.Table3.f)
.Select (LastTable => new {LastTable.Table1, LastTable.Table3});
I have been reading that it can be done with DefaultIfEmpty() or GroupJoin() but i haven't find any complex example with more than one LEFT OUTER JOIN.
Why don't you try using linq query, it is also much easier to write and understand both as compared to lambda expressions. I have on such implementation like:
var products =
from p in this.Products
from cat in this.ProductCategoryProducts
.Where(c => c.ProductID == p.ProductID).DefaultIfEmpty()
from pc in this.ProductCategories
.Where(pc => ac.ProductCategoryID == cat.ProductCategoryID).DefaultIfEmpty()
where p.ProductID == productID
select new
{
ProductID = p.ProductID,
Heading = p.Heading,
Category = pc.ProductCategory
};
return products ;
Related
I need to convert the following query in SQL to LINQ using the method syntax, but I'm getting confused when I try to include the inline query, joins and groupings:
SELECT CL.*, CB.*, CD.*, CC.*, CS.*
FROM clients AS CL
INNER JOIN (
SELECT A.client_id, SUM(A.amount) AS balance
FROM accounts AS A
WHERE A.account_id = 1
GROUP BY A.client_id
HAVING (SUM(A.amount) > 0.015) OR (SUM(A.amount) < -0.015)
) AS CB ON CL.client_id = CB.client_id
INNER JOIN client_details AS CD ON (CL.client_id = CD.client_id) AND (CL.audit_id = CD.audit_id)
LEFT JOIN client_categories AS CC ON CD.client_category_id = CC.client_category_id
LEFT JOIN statuses AS CS ON CD.status_id = CS.status_id
I did get the GROUP BY and HAVING portions working independently of the overall query, but I have not been able to merge this with the rest as an inline query (though I've tried .Any and other LINQ methods):
.Where(a => a.AccountId == 1)
.GroupBy(a => new { a.ClientId })
.Where(ag => ag.Sum(a => a.Amount) > 0.015M || ag.Sum(a => a.Amount) < -0.015M)
.Select(ag => new { Id = ag.Key.ClientId, Balance = ag.Sum(a => a.Amount) })
I have managed to convert it to LINQ using the query syntax, which works perfectly for me, but I need it in the method (Lambda) syntax:
var clients = from c in _context.Clients
join cb in (from a in _context.Accounts
where a.AccountId == 1
group a by new { Id = a.ClientId } into g
where g.Sum(gs => gs.Amount) > 0.015M || g.Sum(gs => gs.Amount) < -0.015M
select new { g.Key.Id, Balance = g.Sum(gs => gs.Amount) }) on c.Id equals cb.Id
join cd in _context.ClientDetails on new { c.Id, c.AuditId } equals new { cd.Id, cd.AuditId }
join cc in _context.ClientCategories on cd.ClientCategoryId equals cc.Id into ccj
from cc in ccj.DefaultIfEmpty()
join cs in _context.Statuses on cd.StatusId equals cs.Id into csj
from cs in csj.DefaultIfEmpty()
select new Client(c, cb.Balance, new ClientDetails(cd, cc, cs));
Any help greatly appreciated.
It appears that LinqPad offers the solution. Run the LINQ query syntax against your database and, when it finishes, click the Lambda symbol at the bottom of the page to see the method syntax:
LinqPad Window
Thanks LinqPad!
I have a SQL statement, that I want to implement in a .NET website project. I don't understand how to join in a particular field, as the fields aren't available when I just select from the table.
My SQL
SELECT *
FROM [vResidence] c
JOIN [vJobs] j on c.UID = j.UID
This is the LINQ I have tried, but I am stuck at the 'ON' part:
results = (from j in vJobs
join cr in vResidence on ??? )
When I try 'j.', the only option I get is 'equals'.
You can follow as this.connect to tables as JOIN use equals keyword
var result = from r in vResidence
join j vJobs on r.UID equals j.UID
select new {[yourcolnum]};
You can try this
var result = (from j in vJobs
join cr in vResidence
on j.UID equals cr.UID
select new {
...
}).ToList();
The Linq expression is the following:
from t1 in Table1
join t2 in Table2
on t1.ID equals t2.ID
The join clause on must be do in order: first the first table, then the second.
The keyword equals must be use.
Apart from the above Linq answers, we can do JOIN using Enumerable.Join extension with Lambda expressions. Try something like,
var result = vJobs.Join(vResidence, jb => new { jb.UID }, res => new { res.UID },
(jb, res) => new { jb, res })
.Select(x => x.jb) //Select the required properties (from both objects) with anonymous object or select left/right object
.ToList();
C# Fiddle with sample data.
I have the follow SQL query
SELECT ob.PK_OBJETIVO,
ev.NM_EVENTO,
ifi.QT_NOTA_IMPACTO,
imi.QT_NOTA_IMPACTO,
ire.QT_NOTA_IMPACTO,
(ifi.QT_NOTA_IMPACTO + imi.QT_NOTA_IMPACTO + ire.QT_NOTA_IMPACTO)/3 AS
Media
FROM AVALIACAO_IMPACTO AS ai
INNER JOIN EVENTO AS EV ON ev.PK_EVENTO = ai.FK_AVALIACAO_IMPACTO_EVENTO
INNER JOIN OBJETIVO AS ob ON ob.PK_OBJETIVO =
ai.FK_AVALIACAO_IMPACTO_OBJETIVO
INNER JOIN IMPACTO_FINANCEIRO AS ifi ON ifi.PK_IMPACTO_FINANCEIRO =
ai.FK_AVALIACAO_IMPACTO_IMPACTO1
INNER JOIN IMPACTO_MISSAO AS imi ON IMI.PK_IMPACTO_MISSAO =
AI.FK_AVALIACAO_IMPACTO_IMPACTO2
INNER JOIN IMPACTO_REPUTACAO AS IRE ON IRE.PK_IMPACTO_REPUTACAO =
AI.FK_AVALIACAO_IMPACTO_IMPACTO3
WHERE ai.FK_AVALIACAO_IMPACTO_OBJETIVO IN
(SELECT OBJ.PK_OBJETIVO
FROM OBJETIVO AS OBJ
WHERE OBJ.FK_OBJETIVO_PROCESSO = 3)
I need to transform that query in a LINQ query, I tried that:
var queryImpactos = await _context.AvaliacaoImpacto
.Where(e => _context.Objetivo.Select(o =>
o.ProcessoID).Contains(planoRiscos.Auditoria.ProcessoID))
.Include(e => e.Evento).Include(e => e.Objetivo)
.Include(e => e.ImpactoFinanceiro).Include(e =>
e.ImpactoMissao).Include(e => e.ImpactoReputacao).ToListAsync();
"planoRiscos.Auditoria.ProcessoID" returns what it takes, the number 3 of the pure SQL query, but the query result is returning all the records in the AVALIACAO_IMPACTO table, however I only need the records where a FK_OBJETIVO in AVALIACAO_IMPACTO exists within the OBJETIVO table, where the FK_PROCESSO in OBJETIVO is equal to the passed parameter (planoRiscos.Auditoria.ProcessoID).
Tip: whenever you need to convert SQL query to a LINQ query, make the query syntax your first choice.
Try this:
var queryImpactos = from ai in AVALIACAO_IMPACTO
join
ev in EVENTO on ai.FK_AVALIACAO_IMPACTO_EVENTO equals ev.PK_EVENTO
join ob in OBJETIVO on ai.FK_AVALIACAO_IMPACTO_OBJETIVO equals ob.PK_OBJETIVO
join ifi in IMPACTO_FINANCEIRO on ai.FK_AVALIACAO_IMPACTO_IMPACTO1 equals ifi.PK_IMPACTO_FINANCEIRO
join imi in IMPACTO_MISSAO on ai.FK_AVALIACAO_IMPACTO_IMPACTO2 equals imi.PK_IMPACTO_MISSAO
join IRE in IMPACTO_REPUTACAO on ai.FK_AVALIACAO_IMPACTO_IMPACTO3 equals IRE.PK_IMPACTO_REPUTACAO
where (from obj in OBJETIVO where obj.FK_OBJETIVO_PROCESSO == 3 select obj.PK_OBJETIVO).Contains(ai.FK_AVALIACAO_IMPACTO_OBJETIVO)
select new
{
ob.PK_OBJETIVO,
ev.NM_EVENTO,
QT_NOTA_IMPACTO1 = ifi.QT_NOTA_IMPACTO,
QT_NOTA_IMPACTO2 = imi.QT_NOTA_IMPACTO,
QT_NOTA_IMPACTO3 = IRE.QT_NOTA_IMPACTO,
Media = (ifi.QT_NOTA_IMPACTO + imi.QT_NOTA_IMPACTO + IRE.QT_NOTA_IMPACTO) / 3
};
Hope it's what you're looking for!
I am trying to perform an outer join in C# using Linq, the person mentoring me keeps saying I shouldn't try to do an outer join which isn't really an answer.
What I got from the other threads is that I need the .DefaultIfEmpty() where ever I may not have a record.
I tried it first on just the lines where there may be a missing information then added it to every line just to see if that was the problem.
Every time I run this I get only the inner join records. It works great other than it is not including the two records from my DB that only have information in the first two tables.
var sqlQuery =
from s in ctx.Suppliers
from sp in ctx.SupplierParts
.Where(sp => sp.SupplierID == s.SupplierID)
.DefaultIfEmpty()
from sm in ctx.SupplierManufacturerRelations
.Where(sm => sm.SupplierPNID == sp.SupplierPNID)
.DefaultIfEmpty()
from mp in ctx.ManufacturerParts
.Where(mp => mp.MfgPNID.Equals(sm.MfgPNID))
.DefaultIfEmpty()
from m in ctx.Manufacturers
.Where(m => m.ManufacturerID.Equals(mp.ManufacturerID))
.DefaultIfEmpty()
from im in ctx.ItemMasters
.Where(im => im.PreID == mp.PreID)
.Where(im => im.PartNumber == mp.PartNumber)
.DefaultIfEmpty()
from c in ctx.ComponentClasses
.Where(c => c.CCID == im.CCID)
.DefaultIfEmpty()
from um in ctx.UnitsOfMeasures
.Where(um => um.UOMID == sp.UOMID)
.DefaultIfEmpty()
select new
{ my variables}
var querylist = sqlQuery.Where(n => n.SupplierID == thisSupplier).ToList();
I also tried
from s in ctx.Suppliers
join sp in ctx.SupplierParts on s.SupplierID equals sp.SupplierID
join sm in ctx.SupplierManufacturerRelations on sp.SupplierPNID equals sm.SupplierPNID into spartgroup
from sm in spartgroup.DefaultIfEmpty()
join mp in ctx.ManufacturerParts on sm.MfgPNID equals mp.MfgPNID into mpartgroup
from mp in mpartgroup.DefaultIfEmpty()
join m in ctx.Manufacturers on mp.ManufacturerID equals m.ManufacturerID into mgroup
from m in mgroup.DefaultIfEmpty()
join im in ctx.ItemMasters
on new { key1 = (int)mp.PreID, key2 = (int)mp.PartNumber }
equals new { key1 = im.PreID, key2 = im.PartNumber }
into tpartgroup
from im in tpartgroup.DefaultIfEmpty()
join c in ctx.ComponentClasses on im.CCID equals c.CCID into fullgroup
from c in fullgroup.DefaultIfEmpty()
join um in ctx.UnitsOfMeasures on sp.UOMID equals um.UOMID
This SQL query works and doesn't omit the rows
SELECT Supplier.SupplierID
, SupplierPart.SupplierPNID
, SupplierPart.SupplierPN
, SupplierPart.Description
, SupplierManufacturerRelation.MfgPNID
, ManufacturerPart.PreID
, ManufacturerPart.PartNumber
, ItemMaster.CCID
, ItemMaster.Description AS Expr1
FROM Supplier
Inner JOIN SupplierPart
ON Supplier.SupplierID = SupplierPart.SupplierID
Left JOIN SupplierManufacturerRelation
ON SupplierPart.SupplierPNID = SupplierManufacturerRelation.SupplierPNID
Left JOIN ManufacturerPart
ON SupplierManufacturerRelation.MfgPNID = ManufacturerPart.MfgPNID
Left JOIN ItemMaster
ON ManufacturerPart.PreID = ItemMaster.PreID
AND ManufacturerPart.PartNumber = ItemMaster.PartNumber
WHERE Supplier.SupplierID = 9
For translating SQL to LINQ query comprehension:
Translate FROM subselects as separately declared variables.
Translate each clause in LINQ clause order, translating monadic operators (DISTINCT, TOP, etc) into functions applied to the whole LINQ query.
Use table aliases as range variables. Use column aliases as anonymous type field names.
Use anonymous types (new { ... }) for multiple columns.
Left Join is simulated by using a into join_variable and doing another from from the join variable followed by .DefaultIfEmpty().
Replace COALESCE with the conditional operator and a null test.
Translate IN to .Contains() and NOT IN to !...Contains()
SELECT * must be replaced with select range_variable or for joins, an anonymous object containing all the range variables.
SELECT fields must be replaced with select new { ... } creating an anonymous object with all the desired fields or expressions.
Proper FULL OUTER JOIN must be handled with an extension method.
So from your SQL, your query should look like:
var ans = from s in ctx.Suppliers
join sp in ctx.SupplierParts on s.SupplierID equals sp.SupplierID
join sm in ctx.SupplierManufacturerRelations on sp.SupplierPNID equals sm.SupplierPNID into smj
from sm in smj.DefaultIfEmpty()
join mp in ctx.ManufacturerParts on sm?.MfgPNID equals mp.MfgPNID into mpj
from mp in mpj.DefaultIfEmpty()
join im in ctx.ItemMasters on new { key1 = (int)mp.PreID, key2 = (int)mp.PartNumber } equals new { key1 = im.PreID, key2 = im.PartNumber } into imj
from im in imj.DefaultIfEmpty()
select new {
s.SupplierID, sp.SupplierPNID, sp.SupplierPN, sp.Description, sm.MfgPNID, mp.PreID, mp.PartNumber, im.CCID, Expr1 = im.Description
};
Struggling with converting a normal SQL Query to a LINQ Query that involves multiple LEFT OUTER JOINS..
Original SQL Query:
SELECT a.*
FROM Testers t
LEFT OUTER JOIN Users u ON u.TesterId = t.TesterId
LEFT OUTER JOIN ValidForms v ON v.DepartmentId = u.DepartmentId
LINQ Query Code is as below:
var x = (from t in Context.Testers.AsEnumerable()
from u in Context.Users
.Where(a => a.TesterId == t.TesterId)
.DefaultIfEmpty()
from v in Context.ValidForms
.Where(b => b.DepartmentId == u.DepartmentId)
.DefaultIfEmpty()
Select new myEntity
{
col1 = t.col1,
col2 = t.col2
}).AsEnumerable()
return x.ToList();
Running the query, I am getting an error: Non-static method requires a target
Appreciate if someone could point out how to do the query properly in LINQ.
I also checked the SO question posted here, but I am unable to grasp the concept provided: SQL to Linq query with multiple left outer joins
Thanks.
Update:
I got this from this SO question.
This is a good way to do it. If you follow that example, your code should look something like this:
var x = (from t in Context.Testers.AsEnumerable()
join u in Context.Users on t.TesterId equals u.TesterId into group1
from a in group1.DefaultIfEmpty()
join v in Context.ValidForms on a.DepartmentId equals v.DepartmentId into group2
from b in group2.DefaultIfEmpty()
select new MyEntity {
col1 = b.col1,
col2 = b.col2
}).AsEnumerable();
UPDATED
var x = (from t in Context.Testers.AsEnumerable()
join u in Context.Users on t.TesterId equals u.TesterId
join v in Context.ValidForms on u.DepartmentId equals v.DepartmentId into group1
from b in group1.DefaultIfEmpty()
select new MyEntity {
col1 = (b != null) ? b.col1 : null,
col2 = (b != null) ? b.col2 : null
}).AsEnumerable();