C# LINQ Select JOIN GroupBy is not working - c#

I am using entityFramework Core and got a LINQ query select, inner join, where and got the results. I need to add GroupBy and it an error. I followed a few posts and mimic their code but I have been stucked.
I am having issue with translating to LINQ
Here is my linq that is working without the GroupBy
var result = this.myDbContent.Table1
.Join(this.Table2,
table1 => table1.myId,
table2 => table2.myId,
(table1 ,table2) => {table1 ,table2}
)
.Join(this.Table3,
table1_table2 => table1_table2.table1.myId,
table3 => table3.myId,
(table1_table2 ,table3) => {tabtable1_table2 e1 ,table3}
)
.Where(
s => s.table1_table2.table1.myId == 1 &&
s.table1_table2.table2.isCompleted == true
)
.Select(s => new
{
MyID = s.table1_table2.table1.myId,
MyDate = s.table1_table2.Table2.CompletedDate
});
This query works and returns records
In the following I added the GroupBy according to another post
var result = this.myDbContent.Table1
.Join(this.Table2,
table1 => table1.myId,
table2 => table2.myId,
(table1 ,table2) => {table1 ,table2}
)
.Join(this.Table3,
table1_table2 => table1_table2.table1.myId,
table3 => table3.myId,
(table1_table2 ,table3) => {tabtable1_table2 e1 ,table3}
)
.Where(
s => s.table1_table2.table1.myId == 1 &&
s.table1_table2.table2.isCompleted == true
)
.GroupBy(s => new
{
MyID = s.table1_table2.table1.myId,
MyDate = s.table1_table2.Table2.CompletedDate
}
)
.Select(s => new
{
MyID = s.Key.myId,
MyDate = s.Key.CompletedDate,
Count = s.Count()
});
When I run this query with the GroupBy, I get an"SYstem.InvalidOperationException
I am trying to add the following SELECT GROUPBY to the working QUERY
Select Count(*) AS Counts, MyID, MYDATE
FROM ( the working query above )
GROUP BY MyID, MYDATE
Thanks

Yourgroup key only has MyID and MyDate fields - the references to the joined tables are gone, so reference those in your select:
.Select(s => new
{
MyID = s.Key.MyID,
MyDate = s.Key.MyDate,
Count = s.Count()
}

Convert it to a list or Enumerable before grouping
var result = this.myDbContent.Table1
.Join(this.Table2,
table1 => table1.myId,
table2 => table2.myId,
(table1 ,table2) => {table1 ,table2}
)
.Join(this.Table3,
table1_table2 => table1_table2.table1.myId,
table3 => table3.myId,
(table1_table2 ,table3) => {tabtable1_table2 e1 ,table3}
)
.Where(
s => s.table1_table2.table1.myId == 1 &&
s.table1_table2.table2.isCompleted == true
).AsEnumerable()
.GroupBy(s => new
{
MyID = s.table1_table2.table1.myId,
MyDate = s.table1_table2.Table2.CompletedDate
}
)
.Select(s => new
{
MyID = s.Key.table1_table2.table1.myId,
MyDate = s.Key.table1_table2.Table2.CompletedDate,
Count = s.Count()
});

Related

LINQ 3 Inner Joins with 1 Left Outer Join

Wondering why LINQ doesn't have a Left Join method. I've been trying to figure this out with myriad examples on SO, but no such luck. The other examples show simple examples with one join. If I group the joins then I only get references to the TradeCountries table in the select statement.
Being new to LINQ, I could've had this done 4 hours ago with a simple SELECT statement, but here I'm am trying to figure out why the LeftJoin method was left out of LINQ.
What does the line with "LeftJoin" need to be changed to make this work?
/*
* GetTop5Distributors
#param int array of series IDs
*/
public List<TopDistributors> Get5TopDistributors(IEnumerable<int> seriesIds)
{
_context = new MySQLDatabaseContext();
var result = _context.TradesTrades
.Join(_context.TradesSeries, tt => tt.SeriesId, ts => ts.Id, (tt, ts) => new { tt, ts })
.Join(_context.TradesTradeDistributors, tsd => tsd.tt.Id, ttd => ttd.TradeId,
(tsd, ttd) => new { tsd, ttd })
.Join(_context.TradesOrganisations, tsdto => tsdto.ttd.DistributorId, to => to.Id,
(tsdto, to) => new { tsdto, to })
.LeftJoin(_context.TradesCountries, tsdc => tsdc.to.CountryId, tc => tc.Id,
(tsdc, tc) => new {tsdc, tc})
.Where(x => seriesIds.Contains(x.tsdc.tsdto.tsd.tt.SeriesId))
.Where(x => x.tsdc.tsdto.tsd.tt.FirstPartyId == null)
.Where(x => x.tsdc.tsdto.tsd.tt.Status != "closed")
.Where(x => x.tsdc.tsdto.tsd.tt.Status != "cancelled")
.GroupBy(n => new { n.tsdc.tsdto.tsd.tt.SeriesId, n.tsdc.tsdto.ttd.DistributorId })
.Select(g =>
new TopDistributors
{
SeriesId = g.Key.SeriesId,
DistributorName = g.Select(i => i.tsdc.to.Name).Distinct().First(),
IsinNickname = g.Select(i => i.tsdc.tsdto.tsd.ts.Nickname).Distinct().First(),
CountryName = g.Select(i => i.tc.Name).Distinct().First(),
CommissionTotal = Math.Ceiling(g.Sum(i => i.tsdc.tsdto.ttd.Commission))
}
)
.OrderByDescending(x => x.CommissionTotal)
.Take(5)
.ToList();
return result;
}
Here's the rather simple select statement that is taking orders or magnitude too long to convert to LINQ.
SELECT
trades_trades.series_id,
trades_organisations.`name`,
trades_series.nickname,
trades_countries.name as Country_Name,
SUM(trades_trade_distributors.commission) as Commission_Total
FROM
trades_trades
JOIN trades_series
ON trades_series.id = trades_trades.series_id
JOIN trades_trade_distributors
ON trades_trades.id = trades_trade_distributors.trade_id
JOIN trades_organisations
ON trades_trade_distributors.distributor_id = trades_organisations.id
LEFT JOIN trades_countries
ON trades_organisations.country_id = trades_countries.id
WHERE trades_trades.series_id IN (
17,
18)
AND trades_trades.first_party_id IS NULL
AND trades_trades.status <> 'closed'
AND trades_trades.status <> 'cancelled'
GROUP BY trades_trades.series_id, trades_trade_distributors.distributor_id
ORDER BY Commission_Total DESC
Following my recipe, here is a more or less straightforward translation of the SQL to LINQ. I moved the where to be near what it constrains, and used let to create a convenient name for the Sum, as LINQ doesn't allow you to forward reference anonymous object members.
var ans = from tt in trades_trades
where new[] { 17, 18 }.Contains(tt.series_id) && tt.first_party_id == null &&
tt.status != "closed" && tt.status != "cancelled"
join ts in trades_series on tt.series_id equals ts.id
join ttd in trades_trade_distributors on tt.id equals ttd.trade_id
join to in trades_orginizations on ttd.distributor_id equals to.id
join tc in trades_countries on to.country_id equals tc.id into tcj
from tc in tcj.DefaultIfEmpty() // GroupJoin -> left join
group new { tt, ts, ttd, to, tc } by new { tt.series_id, ttd.distributor_id } into tradeg
let Commission_Total = tradeg.Sum(trade => trade.ttd.commission)
orderby Commission_Total descending
select new {
tradeg.Key.series_id,
tradeg.First().to.name,
tradeg.First().ts.nickname,
Country_Name = tradeg.First().tc == null ? null : tradeg.First().tc.name,
Commission_Total
};

Join multiple tables and return last record from table 2

I have few tables table1, table2, table3 and table4. All these tables have a relationship MyID. Table2 may have one or more records, but I'm only interested in the last inserted record.
I wrote the following query to get the desired output, however, table2 is still returning more than one record.
var query = (from t1 in table1
join t2 in table2
on t1.MyID equals t2.MyID
into t2Table
join t3 in table3
on t1.MyID equals t3.MyID
into t3Table
join t4 in table4
on t1.MyID equals t4.MyID
into t4Table
where t1.MyID == 1
select new MyViewModel()
{
A = t1.A,
B = t1.B,
C = t1.C,
D = t2Table
.OrderByDescending(x => x.MyDate)
.Select(x => x.D).First(),
E = t2Table
.OrderByDescending(x => x.MyDate)
.Select(x => x.E).First(),
F = t2Table
.OrderByDescending(x => x.MyDate)
.Select(x => x.F).First(),
G = t3Table.Select(c => new TModel()
{
Col1 = c.Col1,
Col1 = c.Col2,
}).ToList(),
H = t4Table.Select(l => new PModel()
{
Col1 = l.Col1,
Col2 = l.Languages.Col2,
}).ToList(),
});
For D, E, F, I have also tried selecting .Max(), but still same result. How can I get the latest record from table2 using join?
Don't use explicit joins. Rewrite your query the following way:
var query = table1
.Where(t1 => t1.MyID == 1)
.Select(t1 => new MyViewModel()
{
A = t1.A,
B = t1.B,
C = t1.C,
D = table2.Where(t2 => t2.MyID == t1.MyID).OrderByDescending(x => x.MyDate).Select(x => x.D).FirstOrDefault(),
E = table2.Where(t2 => t2.MyID == t1.MyID).OrderByDescending(x => x.MyDate).Select(x => x.E).FirstOrDefault(),
F = table2.Where(t2 => t2.MyID == t1.MyID).OrderByDescending(x => x.MyDate).Select(x => x.F).FirstOrDefault(),
G = table3.Where(t3 => t3.MyID == t1.MyID).Select(c => new TModel()
{
Col1 = c.Col1,
Col2 = c.Col2,
}).ToList(),
H = table4.Where(t4 => t4.MyID == t1.MyID).Select(l => new PModel()
{
Col1 = l.Col1,
Col2 = l.Languages.Col2,
}).ToList(),
});
For the moment we'll disregard the possible performance optimizations. This should have your desired result. Also note, that I fixed the assignment for the G property (you had there the Col1 assigned twice. I also switched from using First() to FirstOrDefault() as this should be more safe and robust (although I'm not sure how the MySql will be different).

How to write IQueryable Join using lambda?

I have next table:
MyTable
(
ParentId Integer,
Type Integer,
ProdId String,
Date DateTime,
Status Integer
);
I want to query as next:
var res = from tout in myTable.Where(t1 => t1.Type == 1)
join tin in myTable.Where(t2 => t2.Type != 1)
on tout.ParentId equals tin.ParentId
where tout.ProdId == tin.ProdId && tout.Status > tin.Status
orderby tout.Date
select new MyTableStructure
{
...
};
How to write same as IQueryable using lambda?
Something like this
var query1 = myTable.Where(t1 => t1.Type == 1);
var query2 = myTable.Where(t2 => t2.Type != 1);
var join = query1.Join(query2, x => x.ParentId, y => y.ParentId, (query1, query2) => new { query1 , query2 }).Where(o => o.query1.ProdId == o.qyuery2.prodId).......
your order by next and Something

Entity framework complex query to nested C# object

I am having following query here. how do I get similar linq query for this sql.
SELECT *
FROM PublishedLineBar
WHERE PublishedRosterShiftId
IN (SELECT LatestShiftId FROM
( SELECT MAX(PublishedRosterShiftId) as LatestShiftId, DayNumber
FROM PublishedRosterShift
WHERE employeeid = 14454
GROUP BY DayNumber)
as ShiftProjection )
I have used below linq translation, but it is failing somewhere.
var shifts = dbContext.PublishedRosterShifts
.Where(h => h.EmployeeId == EmployeeId);
var inner = shifts
.Select(x => new
{
LatestShiftId = shifts.Max(p => p.PublishedRosterShiftId),
DayNumber = x.DayNumber
})
.GroupBy(s => s.DayNumber)
.Select(g => g.FirstOrDefault());
var q = from f in shifts
select new
{
LatestShiftId = shifts.Max(p => p.PublishedRosterShiftId),
DayNumber = f.DayNumber
};
var query = from l in dbContext.PublishedLineBars
where inner.Select(s => s.LatestShiftId).Contains(l.PublishedRosterShiftId)
select l;
Here is the LINQ equivalent of your subquery used for SQL IN (...) clause (with unnecessary nesting removed):
var inner = dbContext.PublishedRosterShifts
.Where(s => s.EmployeeId == EmployeeId)
.GroupBy(s => s.DayNumber)
.Select(g => g.Max(s => s.PublishedRosterShiftId));
and the query using it:
var query = from l in dbContext.PublishedLineBars
where inner.Contains(l.PublishedRosterShiftId)
select l;
or simply
var query = dbContext.PublishedLineBars
.Where(l => inner.Contains(l.PublishedRosterShiftId));
What you are missing in your attempt is that in SQL SELECT MAX(PublishedRosterShiftId) as LatestShiftId, DayNumber operates on the result of the GROUP BY operator, hence in LINQ the Select should be after GroupBy.

Entity Framework with Linq, inner Join, Group By, Order By

I have a SQL Query
select Firma.Name as companyName,
Taetigkeit.Taetigkeit as skillName,
SUM(Zeit) as time
from Zeiterfassung
inner join Firma On ZEiterfassung.FirmenID = Firma.ID
inner join Taetigkeit on Zeiterfassung.TaetigkeitID = Taetigkeit.ID
group by Taetigkeit, Firma.Name
order by Firma.Name
And want to "translate" it to linq. Here is what I tried:
var query = db.Zeiterfassung
.Where(x => x.Firma.ID == x.FirmenID && x.TaetigkeitID == x.Taetigkeit.ID)
.GroupBy(x => x.Taetigkeit.Taetigkeit1)
.Select(x => new Evaluation() { skillName = x.Key, time = x.Sum(y => y.Zeit), //skillName = x.Sum(x => x.Zeit), })
.OrderBy(x => x.skillName);
I dont know who to solve this with joins and the group by because all the time when i do a groupBy i cant access the other members.
From data you provided, I think query should look like
from z in db.Zeiterfassung
join f in db.Firma on z.FirmenID equals f.ID
join t in db.Taetigkeit on z.TaetigkeitID equals t.ID
select new { f.Name, t.Taetigkeit, z.Zeit) into x
group x by new { x.Taetigkeit, f.Name } into g
select new {
CompanyName = g.Key.Name,
SkillName = g.Key.Taetigkeit,
Time = g.Sum(i => i.Zeit)
}
Or with navigation properties:
db.Zeiterfassung
.Select(z => new { z.Zeit, z.Taetigkeit.Taetigkeit1, z.Firma.Name })
.GroupBy(x => new { x.Taetigkeit1, x.Name })
.Select(g => new Evaluation {
companyName = g.Key.Name,
skillName = g.Key.Taetigkeit1,
time = g.Sum(y => y.Zeit)
});

Categories

Resources