Convert to Lambda expression - linq

I have the following expression
var q = from c in D1
join dp in
(from e in E1
group e by e.ID into g
select new { ID = g.Key, Cnt = g.Count() })
on c.ID
equals dp.ID
into dpp from v in dpp.DefaultIfEmpty()
select new { c.ID, Cnt= v.Cnt ?? 0 };
How can i convert this to Lambda expression?

Here's one way to go. This kind-of matches the above.
var subquery = E1
.GroupBy(e => e.Id)
.Select(g => new { ID = g.Key, Cnt = g.Count()});
//.ToList();
var q = D1
.GroupJoin(
subquery,
c => c.ID,
dp => dp.ID,
(c, g) => new {ID = c.ID, Cnt=g.Any() ? g.First().Cnt : 0 }
)
After refactoring, I came up with this:
var q = D1
.GroupJoin(
E1,
d => d.ID,
e => e.ID,
(d, g) => new {ID = d.ID, Cnt = g.Count()}
);
For comparision, the query comprehension form is:
var q = from d in D1
join e in E1 on d.ID equals e.ID into g
select new {ID = d.ID, Cnt = g.Count()};

Why would you want to convert it?
For complex queries like this one the query syntax you have used here is invariably clearer.

Related

Left join with LINQ with entityframework

I try to make a left query with linq:
public IQueryable<Mutatie> GetMutaties()
{
var query = (from m in context.Mutatie
join d in context.tblDienstverband on m.fkDienstVerbandID equals d.DienstverbandID
join med in context.tblMedewerker on d.fkMedewerkerID equals med.MedewerkerID
where med.fkKlantID == this.klantId
select m).Include(d => d.fkDienstVerbandID);
return query;
}
But how to make this to have a left query?
Thank you
I have it now like this:
var query = (from m in context.Mutatie
join d in context.tblDienstverband on m.fkDienstVerbandID equals d.DienstverbandID into grp
from d in grp.DefaultIfEmpty()
join med in context.tblMedewerker on d.fkMedewerkerID equals med.MedewerkerID into grp1
from med in grp.DefaultIfEmpty()
where med.fkMedewerkerID == this.klantId
select new { m, d, med });
return query;
It should like this:
NOTE: d and med are null if no row match
public IQueryable<Mutatie> GetMutaties()
{
var query = (from m in context.Mutatie
join d in context.tblDienstverband on m.fkDienstVerbandID equals d.DienstverbandID into grp
from d in grp.DefaultIfEmpty()
join med in context.tblMedewerker on d.fkMedewerkerID equals med.MedewerkerID into grp_med
from med in grp_med.DefaultIfEmpty()
where med.fkKlantID == this.klantId
//select new { m, d, med };
select m;
return query;
}

Linq FirstOrDefault List inside a query

I have this linq query
var numberGroups =
from n in VISRUBs.Where(a => a.VISANA.VISITE.DATEVIS <= d && a.VISANA.VISITE.PANUM == p)
group n by n.RUBRIQUE into g
select new {
RemainderCHAPLIB = g.Key.ANALYSE.CHAPITRE.LIBELLE,
RemainderLIB = g.Key.LIBELLE,
RemainderRUNUM = g.Key.RUNUM,
vals = from vlist in g.OrderByDescending(a=>a.VISANA.VISITE.DATEVIS)
select vlist.VALEUR
};
which gives me this result in Linqpad
What I want is to select the first and second item from the last field (vals) which is a List<string>.
I have tried this:
var numberGroups =
from n in VISRUBs.Where(a => a.VISANA.VISITE.DATEVIS <= d && a.VISANA.VISITE.PANUM == p)
group n by n.RUBRIQUE into g
select new {
RemainderCHAPLIB = g.Key.ANALYSE.CHAPITRE.LIBELLE,
RemainderLIB = g.Key.LIBELLE,
RemainderRUNUM = g.Key.RUNUM,
vals = from vlist in g.OrderByDescending(a => a.VISANA.VISITE.DATEVIS)
select vlist.VALEUR
};
var lst = from n in numberGroups
select new
{
RemainderCHAPLIB = n.RemainderCHAPLIB,
RemainderLIB = n.RemainderLIB,
RemainderRUNUM = n.RemainderRUNUM,
VAL = n.vals.FirstOrDefault()
};
but it didn't work, I got an exception:
Dynamic SQL ErrorSQL error code = -104Token unknown - line 54, column 1OUTER
found it !
var lst = from n in numberGroups.ToList()
select new
{
RemainderCHAPLIB = n.RemainderCHAPLIB,
RemainderLIB = n.RemainderLIB,
RemainderRUNUM = n.RemainderRUNUM,
VAL = n.vals.FirstOrDefault(),
ANT = n.vals.Skip(1).FirstOrDefault()
};

Linq Lambda multiple tables ( 4 tables ) LEFT JOIN

I have 4 tables;
TMain >> MainId (PK)
T1 >> T1_Id, MainId, X (PK and FK) X is decimal
T2 >> T2_Id, MainId, X (PK and FK) X is decimal
T3 >> T3_Id, MainId, X (PK and FK) X is decimal
Here SQL output;
SELECT TMain.*, (ISNULL(T1.X,0) + ISNULL(T2.X,0) + ISNULL(T3.X,0)) AS TOTAL FROM TMain
LEFT OUTER JOIN T1 ON TMain.MainId = T1.MainId
LEFT OUTER JOIN T2 ON TMain.MainId = T2.MainId
LEFT OUTER JOIN T3 ON TMain.MainId = T3.MainId
How can I write it LINQ LAMDA
var AbbA = MyContext.TMain
.GroupJoin(
MyContext.T1,
q1 => q1.TMainId,
q2 => q2.TMainId,
(x, y) => new { A = x, T1_A = y })
.SelectMany(
xy => xy.T1_A.DefaultIfEmpty(),
(x, y) => new { A = x.A, T1_A = y })
.GroupJoin(
MyContext.T2,
q1 => q1.A.TMainId,
q2 => q2.TMainId,
(x, y) => new { A = x, T2_A = y })
.SelectMany(
xy => xy.T2_A.DefaultIfEmpty(),
(x, y) => new { A = x.A, T2_A = y })
.GroupJoin(
MyContext.T3,
q1 => q1.A.A.TMainId,
q2 => q2.TMainId,
(x, y) => new { A = x, T3_A = y })
.SelectMany(
xy => xy.T3_A.DefaultIfEmpty(),
(x, y) => new { A = x.A, T3_A = y })
.Select(q => new
{
TMainId = q.A.A.A.TMainId,
Total = (q.T3_A.X == null ? 0 : q.T3_A.X) +
(q.A.T2_A.X == null ? 0 : q.A.T2_A.X) +
(q.A.A.T1_A.X == null ? 0 : q.A.A.T1_A.X),
}).ToList();
So I want to access T1 fields or TMain fields
I wrote q.A.A.T1_A.X or q.A.A.A. in linq select
Is that true? or have simplest way?
I cannot test now if will work, but sometimes you can write the GroupJoin like (if you expect 0 or N registers from T1):
.GroupJoin(MyContext.T1,
q1 => q1.TMainId,
q2 => q2.TMainId,
(x, y) => new { A = x, T1_A = y.DefaultIfEmpty() })
or (if you expect 0 or 1 registers from T1)
.GroupJoin(MyContext.T1,
q1 => q1.TMainId,
q2 => q2.TMainId,
(x, y) => new { A = x, T1_A = y.FirstOrDefault() })
It always depends what do you like to return for the next lambda, and in this case you don't need the SelectMany(). But this code will be the most simple left join you can get with linq/lambda if you cannot map accordingly the relationship between the tables.
You can simplify if you map the relationship between table TMain and T1 with "HasOptional", like:
modelBuilder.Entity<T1>()
.HasOptional(x => x.TMain)
.WithMany(y => y.T1s)
.HasForeignKey(x => x.TMaidId);
The "HasOptional()" shows to Entity Framework that this relationship are optional, so the LEFT JOIN will be used to mount the query. If you use "HasRequired()", will be used the JOIN.
So, you can use Include():
var AbbA = MyContext.TMain
.Include(x => x.T1s)
To left join T1 and T2:
var AbbA = MyContext.TMain
.Include(x => x.T1s.Select(y => y.T2s))

Using GroupBy, Count and Sum in LINQ Lambda Expressions

I have a collection of boxes with the properties weight, volume and owner.
I want to use LINQ to get a summarized list (by owner) of the box information
e.g.
**Owner, Boxes, Total Weight, Total Volume**
Jim, 5, 1430.00, 3.65
George, 2, 37.50, 1.22
Can someone show me how to do this with Lambda expressions?
var ListByOwner = list.GroupBy(l => l.Owner)
.Select(lg =>
new {
Owner = lg.Key,
Boxes = lg.Count(),
TotalWeight = lg.Sum(w => w.Weight),
TotalVolume = lg.Sum(w => w.Volume)
});
var q = from b in listOfBoxes
group b by b.Owner into g
select new
{
Owner = g.Key,
Boxes = g.Count(),
TotalWeight = g.Sum(item => item.Weight),
TotalVolume = g.Sum(item => item.Volume)
};
var boxSummary = from b in boxes
group b by b.Owner into g
let nrBoxes = g.Count()
let totalWeight = g.Sum(w => w.Weight)
let totalVolume = g.Sum(v => v.Volume)
select new { Owner = g.Key, Boxes = nrBoxes,
TotalWeight = totalWeight,
TotalVolume = totalVolume }

Linq left joining with non trivial condition

This is fine, it produces a left join
var q =
from c in categories
join p in products
on c equals p.Category into ps
from p in ps.DefaultIfEmpty()
select new { Category = c, ProductName = p == null ? "(No products)" : p.ProductName };
But what about if I wanted to do something like this:
...
on p.date between c.startdate and c.enddate
...
var q =
from c in categories
join p in products
on c equals p.Category into ps
from p in ps.DefaultIfEmpty()
where p.date >= c.startdate && p.date <= c.enddate
select new { Category = c, ProductName = p == null ? "(No products)" : p.ProductName };

Resources