How to do linq joins with multiple conditions + ORs - c#

I would like to know how to do a linq join with multiple conditions and ORs.
Example:
var i = (from d in context.Table1
join b in context.Table2
on new {r1 = d.col1, r2 = d.col2}
equals new {r1 = b.col1, r2 = b.col2}
|| b.col3.ToLower() equals "xyz"
into bd
from k in bd.DefaultIfEmpty()
The ORs part is blowing up.
SQL example:
SELECT * FROM Table1 T1
LEFT JOIN Table2 T2 ON (T1.Col1 = T2.Col1 AND T1.Col2 =T2.Col2)
OR (T1.Col1 = T2.Col1 AND T2.Col2 = 'XYZ')
Explanation:
T1.Col1 must match T2.COl1 - REQUIRED JOIN
Then
T1.Col2 has to match T2.Col2 unless T2.COl2 = "XYZ" then join only on Col1

Try moving the "join" into the "Where" clause ala ANSI 82:
var i = (from d in context.Table1
from b in context.Table2
where (b == null)
|| (d.col1 = b.col1 && d.col2 == b.col2 )
|| (b.col3.ToLower() == "xyz")

Related

Fast join on Multiple IEnumerable

Whith s_records, q_records, d_records, i_records all of type IEnumerable<MyRecord>, querytwo works just as expected. But what if I want to join multiple IEnumerable on the same equality of the same fields?
var querytwo = from a in s_records
join b in q_records
on a.date equals b.date
select new { s_line = a.line, q_line = b.line };
Console.WriteLine(querytwo.Count());
This query doesn't work I am trying to do the same as in querytwo, but join on multiple IEnumerable<MyRecord>:
var query = from a in s_records
join b in q_records
join c in d_records
join d in i_records
on a.date equals b.date equals c.date equals d.date
select new { s_line = a.line, q_line = b.line, d_line = c.line, i_line = d.line };
Your syntax is to off to some extent. it should be:
var querytwo = from a in s_records
join b in q_records on a.date equals b.date
join c in d_records on b.date equals c.date
join d in i_records on c.date equals d.date
select new {
s_line = a.line,
q_line = b.line,
d_line = c.line,
i_line = d.line
};

T-SQL to LINQ query that has a case statement and a subquery in it

I'm a complete beginner in LINQ and I would like to convert this T-SQL query in LINQ
SELECT
CASE
WHEN D.IsBaseloadDefined = 1
THEN COUNT(D.DeviceID)
ELSE
(SELECT COUNT(DORG.DeviceID)
FROM DeviceOrganization DORG
INNER JOIN Organization ORG ON DORG.OrganizationID = ORG.OrganizationID
INNER JOIN BaseloadOrganization BO ON ORG.BaseloadOrganizationId = BO.OrganizationID
INNER JOIN Baseload BL ON BO.BaseloadID = BL.BaseloadID
WHERE DORG.DeviceID = D.DeviceID
AND BL.RecursUntil >= GETDATE()
GROUP BY DORG.DeviceID)
END AS [Nb of devices]
FROM DeviceOrganization DO
INNER JOIN Device D ON DO.DeviceID = D.DeviceID
LEFT JOIN BaseloadDevice BD ON D.DeviceID = BD.DeviceID
LEFT JOIN Baseload B ON BD.BaseloadID = B.BaseloadID AND B.RecursUntil >= GETDATE()
INNER JOIN OrganizationHierarchy OH ON DO.OrganizationID = OH.SubOrganizationID
WHERE OH.OrganizationID = 6
AND D.IsActive = 1
group by D.DeviceID, D.IsBaseloadDefined
I've seen this topic but I don't really understand the answer
The only thing I could do so far is this, and now I'm completly lost
from deviceO in _context.DeviceOrganizations
join d in _context.Devices on deviceO.DeviceID equals d.DeviceID
join bd in _context.BaseloadDevices on d.DeviceID equals bd.DeviceID
join b in _context.Baseloads on bd.BaseloadID equals b.BaseloadID
join oh in _context.OrganizationHierarchies on deviceO.OrganizationID equals oh.SubOrganizationID
where oh.OrganizationID == OrganizationId
where d.IsActive == true
where b.RecursUntil <= DateTime.Now
group d.DeviceID by d.DeviceID).Count()
Instead of get count of group
group d.DeviceID by d.DeviceID).Count()
you should save result in variable
var data = from deviceO in _context.DeviceOrganizations
join d in _context.Devices on deviceO.DeviceID equals d.DeviceID
join bd in _context.BaseloadDevices on d.DeviceID equals bd.DeviceID
join b in _context.Baseloads on bd.BaseloadID equals b.BaseloadID
join oh in _context.OrganizationHierarchies on deviceO.OrganizationID equals oh.SubOrganizationID
where oh.OrganizationID == OrganizationId
where d.IsActive == true
where b.RecursUntil <= DateTime.Now
and then you should do something like this:
//group by 2 properties
var result = data.GroupBy(d => new { d.DeviceID, d.IsBaseloadDefined })
.Select(g =>
{
//for each group we get IsBaseloadDefined property
var IsBaseloadDefined = g.Key.IsBaseloadDefined;
if (IsBaseloadDefined == 1)
{
return g.Count();
}
else
{
// here another select that return count:
//(SELECT COUNT(DORG.DeviceID)
//FROM DeviceOrganization DORG
// INNER JOIN Organization ORG ON DORG.OrganizationID = ORG.OrganizationID
//INNER JOIN BaseloadOrganization BO ON ORG.BaseloadOrganizationId = BO.OrganizationID
//INNER JOIN Baseload BL ON BO.BaseloadID = BL.BaseloadID
//WHERE DORG.DeviceID = D.DeviceID
//AND BL.RecursUntil >= GETDATE()
//GROUP BY DORG.DeviceID)
//in this query you should return Count() of group
return 1; //return group.Count() instead 1
}
});
I hope this helps you

Translating a sql Case When statement to LINQ

How can I do this CASE WHEN statement in LINQ ?
SELECT c.nm_grupo, c.cd_grupo, YEAR(GETDATE()),
CASE WHEN (
SELECT SUM(p.valor)
FROM ind_receita p
JOIN ind_equipto o ON p.cd_equipto = o.cd_equipto
JOIN ind_grupo c2 ON o.cd_grupo = c2.cd_grupo
WHERE c2.cd_grupo = c.cd_grupo
AND YEAR(p.dt_emissao) = YEAR(GETDATE())
)
IS NULL THEN 0 ELSE
(
SELECT SUM(p.valor)
FROM ind_receita p
JOIN ind_equipto o ON p.cd_equipto = o.cd_equipto
JOIN ind_grupo c2 ON o.cd_grupo = c2.cd_grupo
WHERE c2.cd_grupo = c.cd_grupo
AND YEAR(p.dt_emissao) = YEAR(GETDATE())
)
END AS valor
FROM ind_grupo c
ORDER BY c.nm_grupo
MY TRY
// SELECT * FROM IND_GRUPO IN LINQ
var GetAllGroups = (from c in _repositorio.GetGrupoEquipamentos()
select c);
// THE SAME SUBQUERY IN LINQ
var MySubQuery= (from p in _repositorio.GetReceitas()
join o in _repositorio.GetEquipamentos() on p.CodigoEquipamento.Equipamento_Id equals o.Equipamento_Id
join a in _repositorio.GetGrupoEquipamentos() on o.CodigoGrupo.Grupo_Id equals a.Grupo_Id
where p.DataHoraCriacaoRegistro.Year == DateTime.Now.Year
&& a.Grupo_Id == GetAllGroups.Select(a => a.Grupo_Id)
select p.Valor).Sum();
First, let's remove the CASE from your SQL: it can be replaced by ISNULL function:
SELECT
c.nm_grupo
, c.cd_grupo
, YEAR(GETDATE())
, ISNULL((
SELECT SUM(p.valor)
FROM ind_receita p
JOIN ind_equipto o ON p.cd_equipto = o.cd_equipto
JOIN ind_grupo c2 ON o.cd_grupo = c2.cd_grupo
WHERE c2.cd_grupo = c.cd_grupo
AND YEAR(p.dt_emissao) = YEAR(GETDATE())
)
, 0) AS valor
FROM ind_grupo c
ORDER BY c.nm_grupo
Now let's convert this to LINQ:
var GetAllGroups = _repositorio
.GetGrupoEquipamentos()
.Select(c => new {
c.nm_grupo // Use C# fields that you mapped to these fields in DB
, c.cd_grupo // Same as above
, valor = (from p in _repositorio.GetReceitas()
join o in _repositorio.GetEquipamentos() on p.CodigoEquipamento.Equipamento_Id equals o.Equipamento_Id
join a in _repositorio.GetGrupoEquipamentos() on o.CodigoGrupo.Grupo_Id equals a.Grupo_Id
where c.Grupo_Id == a.Grupo_Id && p.DataHoraCriacaoRegistro.Year == DateTime.Now.Year
select (decimal?)p.Valor).Sum() ?? 0
});
Note a cast of p.Valor to a nullable decimal. If you want a different type, replace this cast as appropriate.

SQL query to LINQ expression

I cannot make the following query into LINQ expression. Could you help me ?
SELECT Employee_Id_FK from TimeRegistrations as tr
JOIN Employees em ON tr.Employee_Id_FK = em.id
JOIN Managers m ON em.Manager_Id_FK = m.id
WHERE m.id = 4
This is what I have so far :
var result = from t in DB.TimeRegistrations
join Employees in DB.TimeRegistrations on t.Employee_Id_FK equals Employees.id
join Managers in DB.Managers on ..... ;
// Display results.
foreach (var r in result)
{
Console.WriteLine(r);
}
In case your db has foreign keys:
var result =from t1 in DB.TimeRegistrations
join t2 in t1.Employees
join t3 in t2.Managers
where t3.id == "4"
select t1
in case it does not:
var result =from t1 in DB.TimeRegistrations
join t2 in DB.Employees on t1.Employee_Id_FK equals t2.id
join t3 in DB.Managers on t2.id equals t3.Manager_Id_FK
where t3.id == "4"
select t1
However shorter way will be:
var result = DB.Managers.Find(4).Employees.SelectMany(e=>e.TimeRegistrations)
Or not that straight forward way:
var result = DB.TimeRegistrations
.Where(t=>t.Employees.Any(e=>e.Managers.Any(m=>m.id == 4)))

Convert special SQL query to Linq

do you know how write this SQL Query to linq ?
SELECT *
FROM
a
INNER JOIN b
ON a.FkSubmissionId = b.Id
RIGHT JOIN c
ON a.FkItemId = c.Id
WHERE
(b.FkUserId = '...' OR b.FkUserId is null)
and
(c.FkTenderId = 2)
I use Linquer and the best I have from the tool is that :
Linq :
from
items in _context.Items
from
si in _context.si
join s in _context.s
on new { fki = si.fki } equals new { fki = s.Id }
into
submissions_join
from
s in submissions_join.DefaultIfEmpty()
...
Result in SQL :
SELECT *
FROM
[Items] AS [t0]
CROSS JOIN [SubmissionsItems] AS [t1]
LEFT OUTER JOIN [Submissions] AS [t2]
ON [t1].[FkSubmissionId] = [t2].[Id]
WHERE
(([t2].[FkUserId] = #p0) OR (([t2].[FkUserId]) IS NULL))
AND
([t0].[FkTenderId] = #p1)
So the final result it not what I get from the query I need...
Thank you for your help !!!
Try this:
var part1 =
from x in a
join y in b on x.FkSubmissionId equals y.Id
where b.FkUserId = "..."
select new {x, y};
var part2 =
from c in z
where c.FkTenderId == 2
join xy in part1
on z.Id equals xy.x.FkItemId
into xys
from xy in xys.DefaultIfEmpty()
select new {xy.x, xy.y, z};
I would reorder your query so you can use a left join instead of a right join
var query = from c in context.C
from a in context.A.Where(x => c.Id == x.FkItemId)
.DefaultIfEmpty()
join b in context.B on a.FkSubmissionId equals b.id
where b.FkUserId == '...' || b.FkUserId == null
where c.FkTenderId == 2
select new {
a,
b,
c
};

Categories