Convert T-SQL into LINQ Lambda - c#

How can i write this query in LINQ lambda expression or query syntax if required? I have been trying for a while now. The multiple joins are making it difficult. The total records on the join are over 2000 and the final result should be about 15 records
select
year([date]),
month([date]),
sum(ot.rate)
from s as s
join cs cs on cs.s_id= s.id
join ot ot on ot.id = cs.o_id
group by
year([date]),
month([date])
this is the closest I have got but will not compile. I cannot access the ot property from within the select block.
var query = from se in table_se
join cs in table_cs on se.Id equals cs.S_Id
join ot in table_ot on cs.O_Id equals ot.Id
group se by new { se.Date.Year, se.Date.Month } into grp
select new
{
grp.Key.Year,
grp.Key.Month,
grp.Sum(ot.Rate)
};

You were very close - Enumerable.Sum takes a predicate
var query = from se in table_se
join cs in table_cs on se.Id equals cs.S_Id
join ot in table_ot on cs.O_Id equals ot.Id
group ot by new { se.Date.Year, se.Date.Month } into grp
select new
{
Year = grp.Key.Year,
Month = grp.Key.Month,
Sum = grp.Sum(x => x.Rate)
};

Related

Select IN LINQ to entities with inner joins

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!

Linq left join returns inner join

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

Complicated SQL query to Linq

I need to convert the following complicated sql query to Linq in C#:
Select Empleador.NombreComercial as Empresa,
Vacante.Puesto as Vacante,
Vacante.Actividades,
COUNT(Vacante.CveVacante) as Visitas
from Vacante
LEFT JOIN Empleador on Empleador.CveEmpleador=Vacante.CveEmpleador
LEFT JOIN VisitaVacante on Vacante.CveVacante = VisitaVacante.CveVacante
GROUP BY Empleador.NombreComercial,Vacante.Puesto, Vacante.Actividades,
Vacante.CveVacante HAVING COUNT(*) > 1 ORDER BY Visitas DESC
For the moment I already have the following:
var Visitas = (from tvacante in db.VacanteT
join tEmpleador in db.EmpleadorT on tvacante.CveEmpleador equals tEmpleador.CveEmpleador
join tVisitaVacante in db.VisitaVacanteT on tvacante.CveVacante equals tVisitaVacante.CveVacante
select new
{
Empresa = tEmpleador.NombreComercial,
Vacante = tvacante.Puesto,
tvacante.Actividades,
Visitas = tvacante.CveVacante
}).GroupBy( );
How can I add the COUNT(Vacante.CveVacante) as Visitas and also the
GROUP BY Empleador.NombreComercial,Vacante.Puesto, Vacante.Actividades,
Vacante.CveVacante HAVING COUNT(*) > 1 ORDER BY Visitas DESC
to my linq query? I can't find information about how to complete this. The tables are tvacante, templeador, and tvisitaVacante.
Try this:
var Visitas =(from tvacante in db.VacanteT
join tEmpleador in db.EmpleadorT on tvacante.CveEmpleador equals tEmpleador.CveEmpleador
join tVisitaVacante in db.VisitaVacanteT on tvacante.CveVacante equals tVisitaVacante.CveVacante
group new{tEmpleador.NombreComercial,tvacante.Puesto, tvacante.Actividades} by new {tEmpleador.NombreComercial,tvacante.Puesto, tvacante.Actividades} into g
where g.Count()>1
select new
{
Empresa = g.Key.tEmpleador.NombreComercial,
Vacante = g.Key.tvacante.Puesto,
Actividades= g.Key.tvacante.Actividades,
Visitas = g.Count()
}).OrderByDescending(e=>e.Visitas);
If you want to do it using only linq query syntax and not merging both syntax then you could also do this:
var Visitas = from tvacante in db.VacanteT
join tEmpleador in db.EmpleadorT on tvacante.CveEmpleador equals tEmpleador.CveEmpleador
join tVisitaVacante in db.VisitaVacanteT on tvacante.CveVacante equals tVisitaVacante.CveVacante
group new{tEmpleador.NombreComercial,tvacante.Puesto, tvacante.Actividades} by new {tEmpleador.NombreComercial,tvacante.Puesto, tvacante.Actividades} into g
where g.Count()>1
orderby g.Count() descending
select new
{
Empresa = g.Key.tEmpleador.NombreComercial,
Vacante = g.Key.tvacante.Puesto,
Actividades= g.Key.tvacante.Actividades,
Visitas = g.Count()
};

How can I write this query in LINQ

I have this query
SELECT t.NomeTipo, sum(v.QtdProduto)
FROM [dbo].[Vendas] AS V
RIGHT JOIN [dbo].[Produtos] AS P ON V.IdProduto = P.IdProduto
INNER JOIN [dbo].[Tipos] AS T ON P.IdTipo = T.IdTipo
group by t.NomeTipo
order by t.NomeTipo
I have tried this
var queryTipos = from vendas in repositorioVendas.Vendas
join produtos in repositorioProduto.Produtos.DefaultIfEmpty()
on vendas.IdProduto equals produtos.IdProduto
join tipos in repositorioTipo.Tipos
on produtos.IdTipo equals tipos.IdTipo
group vendas by new { tipos.NomeTipo, vendas.QtdProduto }
into novoGrupo
select new
{
NomeTipo = novoGrupo.Key.NomeTipo,
QtdProduto = novoGrupo.Sum(x => x.QtdProduto)
};
With this query I got only two results, but when I run straight from the database I get something like this:
Bebidas 16
Bolos 14
Frios 16
Pães 21
The trick is to realize that you can rewrite your query with a left join instead of a right join by swapping the order of the first two tables and that Linq doesn't have a way to really handle right joins. Also you're grouping was wrong.
var queryTipos = from produtos in repositorioProduto.Produtos
join vendas_pj in repositorioVendas.Vendas
on vendas_pj.IdProduto equals produtos.IdProduto into joined
from vendas in joined.DefaultIfEmpty()
join tipos in repositorioTipo.Tipos
on produtos.IdTipo equals tipos.IdTipo
group vendas by tipos.NomeTipo
into novoGrupo
select new
{
NomeTipo = novoGrupo.Key,
QtdProduto = novoGrupo.Sum(x => x.QtdProduto)
};
Basically a Left join in SQL
From TableA
Left Join TableB
On TableA.ID = TableB.ID
is done in Linq like this
from a in repo.TableA
join b_pj in repo.TableB
on a.ID equals b_pj.ID into joined
from b in joined.DefaultIfEmpty()

Linq to sql Distinct after join

I have a join query and i want to filter the result of this query by using distinct. I want to get only one of the shoes which has same brand, model, primary color and secondary color. How can i make this ? Here is my join query.
var query = from b in db.BrandTbls.AsQueryable()
join m in db.ShoeModelTbls on b.BrandID equals m.BrandID
join s in db.ShoeTbls on m.ModelID equals s.ModelID
join i in db.ShoeImageTbls on s.ShoeID equals i.ShoeID
where s.Quantity > 0
orderby m.ModelName
select new
{
s.ShoeID,
m.ModelName,
m.Price,
b.BrandName,
i.ImagePath
};
I found the solution. This query does approximately what i want to do
var query = from b in db.BrandTbls.AsQueryable()
join m in db.ShoeModelTbls on b.BrandID equals m.BrandID
join s in db.ShoeTbls on m.ModelID equals s.ModelID
join i in db.ShoeImageTbls on s.ShoeID equals i.ShoeID
group new {b,m,s,i} by new {b.BrandName,m.ModelName,m.Price,s.ShoeID,s.PrimaryColor,s.SecondaryColor,i.ImagePath} into g
select new {g.Key.ShoeID,g.Key.BrandName,g.Key.ModelName,g.Key.ImagePath,g.Key.Price};
Remove price from the output and use Distinct() like this:
var query = (from b in db.BrandTbls.AsQueryable()
join m in db.ShoeModelTbls on b.BrandID equals m.BrandID
join s in db.ShoeTbls on m.ModelID equals s.ModelID
join i in db.ShoeImageTbls on s.ShoeID equals i.ShoeID
where s.Quantity > 0
orderby m.ModelName
select new
{
s.ShoeID,
m.ModelName,
b.BrandName,
i.ImagePath
}).Distinct();

Categories