Entity framework complex query to nested C# object - c#

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.

Related

Grouping and Sum some field with Sub query in LINQ

I'm trying to convert my sql query to linq, i confused about sum and grouping,
this is my query
SELECT
produk.supplier,
SUM(transaksi.jumlah_transaksi),
SUM(transaksi.nominal_transaksi),
operasional.nominal
FROM
transaksi INNER JOIN produk ON transaksi.id_produk = produk.id_produk
LEFT JOIN
(SELECT
operasional.id_supplier,
SUM(nominal) AS nominal
FROM
operasional) operasional
ON operasional.id_supplier = produk.id_supplier
GROUP BY produk.supplier
output should be
like this
Progress
i am just trying with linq query like this without grouping
var result = from t in db.transaksi
join p in db.produk on t.id_produk equals p.id_produk
from op in
(
from o in db.operasional
select new
{
id_supplier = o.id_supplier,
nominal = o.nominal
}
).Where(o => o.id_supplier == p.id_supplier).DefaultIfEmpty()
select new
{
nama_supplier = p.supplier,
jumlah_transaksi = t.jumlah_transaksi,
nominal_transaksi = t.nominal_transaksi,
biaya_operasional = op.nominal
};
and result query from my linq still like this
SELECT
`p`.`supplier`,
`t`.`jumlah_transaksi`,
`t`.`nominal_transaksi`,
`t1`.`nominal`
FROM
`transaksi` `t`
INNER JOIN `produk` `p`
ON `t`.`id_produk` = `p`.`id_produk`
LEFT JOIN `operasional` `t1`
ON `t1`.`id_supplier` = `p`.`id_supplier`
Solved
and this is my full linq
var result = from t in db.transaksi
join p in db.produk on t.id_produk equals p.id_produk
from op in
(
from o in db.operasional
group o by o.id_supplier into g
select new
{
id_supplier = g.First().id_supplier,
nominal = g.Sum(o => o.nominal)
}
).Where(o => o.id_supplier == p.id_supplier).DefaultIfEmpty()
select new
{
nama_supplier = p.supplier,
jumlah_transaksi = t.jumlah_transaksi,
nominal_transaksi = t.nominal_transaksi,
biaya_operasional = op.nominal
};
var grouped = result
.GroupBy(x => x.nama_supplier)
.Select(x => new
{
nama_supplier = x.Key,
jumlah_transaksi = x.Sum(s => s.jumlah_transaksi),
nominal_transaksi = x.Sum(s => s.nominal_transaksi),
biaya_operasional = x.Select(s => s.biaya_operasional).First()
});
Try to use GroupBy (in following code result is your query from code above):
var grouped = result
.GroupBy(x => x.nama_supplier)
.Select(x => new {
nama_supplier = x.Key,
sum1 = x.Sum(s => s.jumlah_transaksi),
sum1 = x.Sum(s => s.nominal_transaksi),
nominal = x.Select(s => s.biaya_operasional).First()
})
Code is not checked so use it just as idea.

How can I transform this SQL query to LINQ?

How can I transform this SQL query to LINQ?
SELECT eg.Name Name, sum(bi.PlannedAmount) Amount
FROM BudgetItem bi, Expense e, ExpenseGroup eg
WHERE Discriminator = 'ExpenseItem' AND
bi.ExpenseId = e.Id AND
e.ExpenseGroupId = eg.id AND
bi.MonthlyBudgetId = 1
GROUP BY eg.Name
So far I've come up with this line:
var result = context
.ExpenseGroups
.GroupBy(eg => eg.Id, (s) => new { Name = s.Name, Amount = s.Expenses.SelectMany(e => e.Items).Sum(i => i.PlannedAmount) })
.ToList();
But I still cannot figure out what expression to use to add 'bi.MonthlyBudgetItem = 1'.
Does anybody have an Idea?
Edit #1:
I forgot to mention the relationships between the entities. Every ExpenseGroup has many Expenses, and every Expense has many BudgetItems.
So, ExpenseGroup => Expenses => BudgetItems
Edit #2:
I'm using Entity Framework and every ExpenseGroup has a Collection of Expense objects (every Expense has a ExpenseGroup object), as well as every Expense has a Collection of BudgetItem objects (every BudgetItem object has a Expense object).
I suppose something like this should do it:
var result = context
.ExpenseGroups
.Where(x => x.Discriminator == 'ExpenseItem' &&
x.bi.ExpenseId == e.Id &&
x.e.ExpenseGroupId == eg.id &&
x.bi.MonthlyBudgetId == 1)
.GroupBy(eg => eg.Id, (s) => new { Name = s.Name, Amount = s.Expenses.SelectMany(e => e.Items).Sum(i => i.PlannedAmount) })
.ToList();
Something similar to this...
var result = (from g in context.ExpenseGroups
where g.Expense.BudgetItem.MonthlyBudgetId == 1
select g)
.GroupBy(eg => eg.Id, (s) => new { Name = s.Name, Amount = s.Expenses.SelectMany(e => e.Items).Sum(i => i.PlannedAmount) })
.ToList();
or
var result = context.ExpenseGroups
.Where(g => g.Expense.BudgetItem.MonthlyBudgetId == 1)
.GroupBy(eg => eg.Id, (s) => new { Name = s.Name, Amount = s.Expenses.SelectMany(e => e.Items).Sum(i => i.PlannedAmount) })
.ToList();
You are actually doing an inner join in your SQL query, so do similarly in your linq query as well. This should work:-
var result = from bi in context.BudgetItem
join e in context.Expense
on bi.ExpenseId equals e.Id
where bi.MonthlyBudgetId == 1
join eg in ExpenseGroup
on e.ExpenseGroupId equals eg.id
group new { bi, eg } by eg.Name into g
select new
{
Name = g.Key,
Amount = g.Sum(x => x.bi.PlannedAmount)
};

Converting SQL to Linq with groupby, sum and count

I would like to do a group by and on that a sum and a count. I don't seem to be able to create the solution in linq. How can I convert my query to linq?
SELECT HistoricalBillingProductGroup,
COUNT(*),
BillingPeriod,
SUM(TotalMonthlyChargesOtcAndMrc)
FROM [x].[dbo].[tblReport]
group by BillingPeriod, HistoricalBillingProductGroup
order by BillingPeriod
This is what I got sofar in Linq
var result =
context.Reports.GroupBy(x => new {x.BillingPeriod, x.HistoricalBillingProductGroup})
.Select(x => new StatisticsReportLine
{
HistoricalBillingGroup = x.FirstOrDefault().HistoricalBillingProductGroup,
BillingPeriod = x.FirstOrDefault().BillingPeriod,
CountOfRows = x.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
})
.ToString();
The query I get from this is enormous and takes a very long time to load. In SQL its a matter of milliseconds. I hardly doubt this is the solution.
I believe the calls to x.FirstOrDefault() are the source of your problem. Each one of these will result in a very costly inner query inside the SELECT clause of the generated SQL.
Try using the Key property of the IGrouping<T> instead :
var result = context.Reports
.GroupBy(x => new {x.BillingPeriod, x.HistoricalBillingProductGroup})
.OrderBy(x => x.Key.BillingPeriod)
.Select(x => new StatisticsReportLine
{
HistoricalBillingProductGroup = x.Key.HistoricalBillingProductGroup,
BillingPeriod = x.Key.BillingPeriod,
CountOfRows = x.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
});
Or if you prefer query syntax:
var result =
(from r in context.Reports
group r by new { r.BillingPeriod, r.HistoricalBillingProductGroup } into g
orderby g.Key.BillingPeriod
select new StatisticsReportLine
{
HistoricalBillingProductGroup = g.Key.HistoricalBillingProductGroup,
BillingPeriod = g.Key.BillingPeriod,
CountOfRows = g.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
});
You could try this one:
var result = context.Reports
.GroupBy(x => new {x.BillingPeriod, x.HistoricalBillingProductGroup})
.Select(x => new StatisticsReportLine
{
HistoricalBillingGroup = x.Key.HistoricalBillingProductGroup,
BillingPeriod = x.Key.BillingPeriod,
CountOfRows = x.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
}).ToString();
In the above query you make a group by on two properties, BillingPeriod and HistoricalBillingProductGroup. So in each group that will be created, you will have a key, that will be consisted by these two properties.

How do I get a lambda query that is like this tsql query?

Having a T-SQL query:
select [ProductNumber] ,max([ProductRevNumber])
from Products
group by [ProductNumber]
Attempted LINQ query:
ProductsDBContext.Products.GroupBy(x => x.ProductRevNumber)
.Select(group => ProductNumber,
ProductRevNumber = group.Max(x => x.ProductRevNumber));
The lambda query doesn't work.
I think this is what you are after:
var latestProducts = ProductsDBContext.Products
.GroupBy(p => p.ProductNumber).Select(g => new
{
ProductNumber = g.Key,
MaxProductRevNumber = g.Max(p => p.ProductRevNumber))
});
from p in db.Products
group p by p.ProductNumber into g
select new
{
ProductNumber = g.Key,
ProductRevNumber = g.Max(p => p.ProductRevNumber)
};

How can I write the following code more elegantly using LINQ query syntax?

How can I write the following code more elegantly using LINQ query syntax?
var mergedNotes = new List<Note>();
var noteGroupsByUserID = notes.GroupBy( x => x.UserID );
foreach (var group in noteGroupsByUserID)
{
var sortedNotesByOneUser = group.OrderBy( x => x.CreatedOn ).ToList();
var mergedNotesForAUserID = GetMergedNotesFor( sortedNotesByOneUser );
mergedNotes.AddRange( mergedNotesForAUserID );
}
return mergedNotes;
Not LINQ syntax, but at least more elegant...
List<Note> mergedNotes =
notes
.GroupBy(x => x.UserID)
.SelectMany(g => GetMergedNotesFor(g.OrderBy(x => x.CreatedOn)))
.ToList();
With my test data it creates the same result as your original code.
I think this does the trick:
var mergedNotes = new List<Note>();
mergedNotes.AddRange((from n in notes
orderby n.CreatedOn
group n by n.UserID into g
let m = GetMergedNotesFor(g)
select m).SelectMany(m => m));
return mergedNotes;

Categories

Resources