LINQ Query Order by Month name non-alphabetically - entity-framework

How do I order this query by month not alphabetically? I have two columns in my db. One for the month name and one for month number.
Right now it orders months alphabetically.
var querythpmsick = (from r in db.SickLeaveRequestForms
where r.EmployeeID == id
group r by r.MonthOfHoliday into g
select new { Value = g.Key, Count1 = g.Sum(h => h.SickLeaveTaken) }
).OrderBy(e => e.Value);

If you have both the month name and the month number in your DB, then just group by the number instead of the month name:
var querythpmsick = (from r in db.SickLeaveRequestForms where r.EmployeeID == 2
group r by r.MonthOfHolidayInt into g
select new { Value = g.Key, Count1 = g.Sum(h => h.SickLeaveTaken), MonthName = g.Select(d => d.MonthOfHoliday) })
.OrderBy(e => e.Value);
Here is a DotNetFiddle with the example: https://dotnetfiddle.net/6vE4lo

Related

Easiest way to delete all records except the last 10 by date using EFCore [duplicate]

Let's say that I have a table like:
Id Name Category CreatedDate
1 test test 10-10-2015
2 test1 test1 10-10-2015
...
Now, I would like to delete all rows and leave only the top 10 from all categories (by top 10 I mean the 10 newest according to createdDate).
Using raw SQL, it would be like:
DELETE FROM [Product]
WHERE id NOT IN
(
SELECT id FROM
(
SELECT id, RANK() OVER(PARTITION BY Category ORDER BY createdDate DESC) num
FROM [Product]
) X
WHERE num <= 10
How is this done when using the DbContext in Entity Framework?
// GET all products
var list = ctx.Products.ToList();
// GROUP by category, ORDER by date descending, SKIP 10 rows by category
var groupByListToRemove = list.GroupBy(x => x.Category)
.Select(x => x.OrderByDescending(y => y.CreatedDate)
.Skip(10).ToList());
// SELECT all data to remove
var listToRemove = groupByListToRemove.SelectMany(x => x);
// Have fun!
ctx.Products.RemoveRange(listToRemove);
Guessing it will take a whil if you have a lot of data but.
var oldItems = efContext.Products
.GroupBy(x => x.Category,
(c,p) => p.OrderByDescending(x => p.createdDate).Skip(10))
.SelectMany(p => p);
efContext.Products.RemoveRange(oldItems);
Will do the trick
(Written in notepad)

Entity Framework equivalent of datepart(qq, getdate)

I have the following SQL query which I want to translate to EF query
Select Year(_r.IssueDate) as Year, datepart(qq, _r.IssueDate) as Quarter,count(*) as TotalBillableRecords, SUM(_r.BillableHours) as TotalHOurs
FROM
(select _b.Name, _i.IssueDate, _ie.BillableHours from Beneficiaries _b
join [Beneficiaries.Invoices] _i on _b.Id = _i.BeneficiaryId
join [Beneficiaries.Invoices.Entries] _ie on _ie.InvoiceId = _i.Id
where BeneficiaryId = 1) as _r
group by Year(_r.IssueDate), datepart(qq, _r.IssueDate)
This results in this
And this is what I would also want to have in my linq expression
How can I translate this to EF query ? I've tried like so
var query =
from beneficiary in _dbContext.Beneficiaries
where beneficiary.Id == beneficiaryId
from invoice in beneficiary.Invoices
//where invoice.IssueDate >= since
//where invoice.IssueDate.Month > notBefore && invoice.IssueDate.Month <= notAfter
from invoiceEntry in invoice.InvoiceEntries
group new
{
beneficiary,
invoiceEntry,
}
by new
{
Year = beneficiary.InvoiceMeta.IssueDate.Year,
Quarter = (beneficiary.InvoiceMeta.IssueDate.Month - 1) / 3 + 1,
}
into #group
select new
{
Year = #group.Key.Year,
Quarter = #group.Key.Quarter,
Hours = #group.Sum(x => x.invoiceEntry.BillableHours),
};
var y = query.ToList();
But the result is as following
[0] = Quarter = 3, Year = 2022, Hours = 6729.0
And this is it, only one entry.
What I'm noticing is that it only takes the last quarter composed of 3 months, (because the last would be the one which is not finished yet)
The class hierarchy is
Beneficiary 1-* Invoice 1-* Entries

Is there a way to use `COUNT(DISTINCT)` in EF Core 3.1?

I have a table with the following data
ID DateColumn Amount
1 2021-01-25 50
2 2021-01-24 10
1 2021-01-25 100
I need the following output,
ID DayCount TotalAmount
1 1 150
2 1 10
I'm trying to lambda expression that would generate the following SQL query,
select ID, Count(distinct DateColumn) as DayCount, Sum(Amount) as TotalAmount
from test
group by id
I've writte the following expression,
return await _context.Tests
.GroupBy(g => g.id)
.Select(s => new
{
Data = s.Key,
Count = s.Select(t => t.DateColumn).Distinct().Count()
}).ToListAsync();
and it throws the InValidOperation exception.
There seems to be an error in the resulting table for the first record, which should have a value of 2 for the DayCount.
The resting table construction looks like it could use some rearchitecting due to the Id column containing duplicates.
Regardless of structure, you can use an inner GROUP BY to achieve similar results:
return await _context.Tests
.GroupBy(g => g.id)
.Select(s => new
{
Data = s.Key,
Count = s.GroupBy(t => t.DateColumn).Select(g => g.key).Count()
})
.ToListAsync();

Using group in Entity Framework to return model and count

I have some data, similar to this
Email Date Id
Anne 1/1/00 1
Anne 1/2/00 2
Anne 1/4/00 3
Bert 1/4/00 4
Bert 1/5/00 5
I'm trying to return the following 2 results from the above into something like
List<Model, Count>
Where Model is a class with Email and Date (most recent Date) properties, and count is the total count
var m = (from e in emailOpens
group e by e.EmailAddress into g
select new
{
Model = g.Key,
Occurance = g.Count()
}).ToList();
The issue is, the above will return only the email addresses but I change the group statement to
group e by e into g
Then naturally there is nothing to count, so my Occurrence property remains at 0
What am I missing here?
You are missing just one statement:
var m = (from e in emailOpens
group e by e.EmailAddress into g
select new
{
Model = new
{
Email = g.Key,
// Select maximum date from group
MostRecentDate = g.Max(m => m.Date)
},
Occurance = g.Count()
}).ToList();

How to get multiple sums that are subqueries

Im using Linqpad to test out my EF query and I cant seem to get my end result to include a few extra columns that represent sums of a field based on different conditions
StorePaymentInvoices table contains a FK over to CustomerStatementBatchPayments. So I need to sum the CustomerStatementBatchPayment.net field if there is a corresponding value in StorePaymentInvoices
Getting the sums is turning out to be a real mess. Any suggestions?
Sometimes what is hard to do in one statement, ends up being easier done in multiple steps.
var retval = (
from a in CustomerStatementBatches
join b in CustomerStatementBatchPayments on a.ID equals b.CustomerStatementBatchID into grp1
from c in grp1
where a.CustomerStatementID == StatementId
group c by c.CustomerStatementBatchID into grp2
from e in grp2
select new {
StatementId = e.CustomerStatementBatch.CustomerStatementID,
BatchId = e.CustomerStatementBatchID,
Applied = CustomerStatementBatchPayments.Where(csbp => !StorePaymentInvoices.Select (pi => pi.CustomerStatementBatchPaymentID ).ToList().Contains(e.ID)).Sum (csbp => csbp.Net )
}
).ToList();
retval.Dump();
[ UPDATE 1]
This is what Ive done to get the "conditional" sum values and I seem to be getting the correct numbers. The resulting SQL that it generates is kinda ugly, but executes in < 1 second.
var retval1 = (
from a in CustomerStatementBatches
join b in CustomerStatementBatchPayments on a.ID equals b.CustomerStatementBatchID into grp1
from c in grp1
where a.CustomerStatementID == StatementId
group c by new { a.CustomerStatementID, c.CustomerStatementBatchID} into grp2
from e in grp2.Distinct()
select new {
StatementId = e.CustomerStatementBatch.CustomerStatementID,
BatchId = e.CustomerStatementBatchID
}
).ToList()
.Distinct()
.Select(a => new
{
StatementId = a.StatementId,
BatchId = a.BatchId,
AppliedTotal = (from b in CustomerStatementBatchPayments.Where(r => r.CustomerStatementBatchID == a.BatchId)
join c in StorePaymentInvoices on b.ID equals c.CustomerStatementBatchPaymentID
group b by b.CustomerStatementBatchID into g1
from d in g1
select new{ Total = (decimal?)d.Net}).DefaultIfEmpty().Sum (at => (decimal?)at.Total ) ?? 0.0m,
Unappliedtotal = (from b in CustomerStatementBatchPayments.Where(r => r.CustomerStatementBatchID == a.BatchId)
.Where(s => !StorePaymentInvoices.Any (pi => pi.CustomerStatementBatchPaymentID == s.ID ) )
select new{ Total = (decimal?)b.Net}).DefaultIfEmpty().Sum (at => (decimal?)at.Total ) ?? 0.0m
})
.ToList();
Try this
from a in db.CustomerStatementBatches
join b in db.CustomerStatementBatchPayments
//.Where(i => ...)
.GroupBy(i => i.CustomerStatementBatchesId)
.Select(i => new {
CustomerStatementBatchesId = i.Key,
SumOfPayments = i.Sum(t => t.Net)
}
)
into tmp from b in tmp.DefaultIfEmpty()
on a.CustomerStatementBatchesId equals b.CustomerStatementBatchesId
select new
{
StatementId = a.CustomerStatementId,
BatchId = a.CustomerStatementBatchId,
Applied = ((b == null) ? 0 : b.SumOfPayments)
}