as you can see, i'm trying to perform multiple order by statements at the end of the statement. my results are not coming back correct.
var query =
(from x in workloadDetail
group x by new { x.titleOrder, x.httitle } into sortedData
select new WorkloadSummary()
{
httitle = sortedData.Key.httitle,
totalHrs = sortedData.Sum(x => x.totalHrs),
totalDol = sortedData.Sum(x => x.totalDol),
titleOrder = sortedData.Key.titleOrder
}).OrderBy(x => x.httitle).OrderByDescending(x => x.totalHrs);
If you are chaining multiple OrderBy() queries, you need to use ThenBy() and ThenByDescending() for subsequent properties for them to be applied in the proper order :
.OrderBy(x => x.httitle).ThenByDescending(x => x.totalHrs);
use ThenByDescending method to apply secondary sorting in descending order.
.OrderBy(x => x.httitle).ThenByDescending(x => x.totalHrs);
Related
How would you write a linq query with the following SQL statement. I've tried several methods referenced on stackoverflow but they either don't work with the EF version I'm using (EF core 3.5.1) or the DBMS (SQL Server).
select a.ProductID, a.DateTimeStamp, a.LastPrice
from Products a
where a.DateTimeStamp = (select max(DateTimeStamp) from Products where a.ProductID = ProductID)
For reference, a couple that I've tried (both get run-time errors).
var results = _context.Products
.GroupBy(s => s.ProductID)
.Select(s => s.OrderByDescending(x => x.DateTimeStamp).FirstOrDefault());
var results = _context.Products
.GroupBy(x => new { x.ProductID, x.DateTimeStamp })
.SelectMany(y => y.OrderByDescending(z => z.DateTimeStamp).Take(1))
Thanks!
I understand you would like to have a list of the latest prices of each products?
First of all I prefer to use group by option even over 1st query
select a.ProductID, a.DateTimeStamp, a.LastPrice
from Products a
where a.DateTimeStamp IN (select max(DateTimeStamp) from Products group by ProductID)
Later Linq:
var maxDateTimeStamps = _context.Products
.GroupBy(s => s.ProductID)
.Select(s => s.Max(x => x.DateTimeStamp)).ToArray();
var results = _context.Products.Where(s=>maxDateTimeStamps.Contains(s.DateTimeStamp));
-- all assuming that max datetime stamps are unique
I've managed to do it with the following which replicates the correlated sub query in the original post (other than using TOP and order by instead of the Max aggregate), though I feel like there must be a more elegant way to do this.
var results = from x
in _context.Products
where x.DateTimeStamp == (from y
in _context.Products
where y.ProductID == x.ProductID
orderby y.DateTimeStamp descending
select y.DateTimeStamp
).FirstOrDefault()
select x;
I prefer to break up these queries into IQueryable parts, do you can debug each "step".
Something like this:
IQueryable<ProductOrmEntity> pocoPerParentMaxUpdateDates =
entityDbContext.Products
//.Where(itm => itm.x == 1)/*if you need where */
.GroupBy(i => i.ProductID)
.Select(g => new ProductOrmEntity
{
ProductID = g.Key,
DateTimeStamp = g.Max(row => row.DateTimeStamp)
});
//// next line for debugging..do not leave in for production code
var temppocoPerParentMaxUpdateDates = pocoPerParentMaxUpdateDates.ToListAsync(CancellationToken.None);
IQueryable<ProductOrmEntity> filteredChildren =
from itm
in entityDbContext.Products
join pocoMaxUpdateDatePerParent in pocoPerParentMaxUpdateDates
on new { a = itm.DateTimeStamp, b = itm.ProductID }
equals
new { a = pocoMaxUpdateDatePerParent.DateTimeStamp, b = pocoMaxUpdateDatePerParent.ProductID }
// where
;
IEnumerable<ProductOrmEntity> hereIsWhatIWantItems = filteredChildren.ToListAsync(CancellationToken.None);
That last step, I am putting in an anonymous object. You can put the data in a "new ProductOrmEntity() { ProductID = pocoMaxUpdateDatePerParent.ProductID }...or you can get the FULL ProductOrmEntity object. Your original code, I don't know if getting all columns of the Product object is what you want, or only some of the columns of the object.
SELECT
[TimeStampDate]
,[User]
,count(*) as [Usage]
FROM [EFDP_Dev].[Admin].[AuditLog]
WHERE [target] = '995fc819-954a-49af-b056-387e11a8875d'
GROUP BY [Target], [User] ,[TimeStampDate]
ORDER BY [Target]
My database table has the columns User, TimeStampDate, and Target (which is a GUID).
I want to retrieve all items for each date for each user and display count of entries.
The above SQL query works. How can I convert it into LINQ to SQL? Am using EF 6.1 and my entity class in C# has all the above columns.
Create Filter basically returns an IQueryable of the entire AuditLogSet :
using (var filter = auditLogRepository.CreateFilter())
{
var query = filter.All
.Where(it => it.Target == '995fc819-954a-49af-b056-387e11a8875d')
.GroupBy(i => i.Target, i => i.User, i => i.TimeStamp);
audits = query.ToList();
}
Am not being allowed to group by on 3 columns in LINQ and I am also not sure how to select like the above SQL query with count. Fairly new to LINQ.
You need to specify the group by columns in an anonymous type like this:-
var query = filter.All
.Where(it => it.Target == '995fc819-954a-49af-b056-387e11a8875d')
.GroupBy(x => new { x.User, x.TimeStampDate })
.Select(x => new
{
TimeStampDate= x.Key.TimeStampDate,
User = x.Key.User,
Usage = x.Count()
}).ToList();
Many people find query syntax simpler and easier to read (this might not be the case, I don't know), here's the query syntax version anyway.
var res=(from it in filter.All
where it.Target=="995fc819-954a-49af-b056-387e11a8875d"
group it by new {it.Target, it.User, it.TimeStampDate} into g
orderby g.Key.Target
select new
{
TimeStampDate= g.Key.TimeStampDate,
User=g.Key.User,
Usage=g.Count()
});
EDIT: By the way you don't need to group by Target neither OrderBy, since is already filtered, I'm leaving the exact translation of the query though.
To use GroupBy you need to create an anonymous object like this:
filter.All
.Where(it => it.Target == '995fc819-954a-49af-b056-387e11a8875d')
.GroupBy(i => new { i.Target, i.User, i.TimeStamp });
It is unnecessary to group by target in your original SQL.
filter.All.Where( d => d.Target == "995fc819-954a-49af-b056-387e11a8875d")
.GroupBy(d => new {d.User ,d.TimeStampDate} )
.Select(d => new {
User = d.Key.User,
TimeStampDate = d.Key.TimeStampDate,
Usage = d.Count()
} );
This LINQ-to-SQL query works (testing in LINQpad):
var q5 = LOGs.Where(r => r.APP_NAME == "Toaster")
.GroupBy(pol => pol.CASE_NO)
.Select(grp => grp.First())
.OrderByDescending(l => l.WHEN);
q5.Dump();
However, that returns all columns for each row.
How can I refine the Select() part to specify certain columns?
I can do it in two steps by adding .ToList() to the query, then querying q5:
var q5a = q5.Select(r => new {CASE=r.CASE_NO, WHEN = r.WHEN});
q5a.Dump();
Can I accomplish that in one statement instead of two?
Thanks --
why don't you filter after where?
var q5 = LOGs.Where(r => r.APP_NAME == "Toaster")
.Select(r=> new{r.CASE_NO, r.WHEN})
.GroupBy(pol => pol.CASE_NO)
.Select(grp => grp.First())
.OrderByDescending(l => l.WHEN);
remembar that new {CASE=r.CASE_NO, WHEN = r.WHEN} creates a new anonymous type because of differents property names, new {r.CASE_NO, r.WHEN} doesn't !
I cannot seem to combine 2 GroupBy statements in 1 linq expression..
For now i'm doing something like this:
double maxInvestment = 0;
foreach (var playerAction in TotalUserActions.GroupBy(p => p.Player))
{
var MaxInvestmentPerPlayer = playerAction.GroupBy(p => p.RoundId)
.Select(p => p.LastOrDefault())
.Sum(p=> p.BetSize);
if(MaxInvestmentPerPlayer > maxInvestment)
maxInvestment = MaxInvestmentPerPlayer;
}
What I would like to do is something like this...
double maxInvestment = TotalUserActions.GroupBy(p => p.Player)
.GroupBy(p => p.RoundId)
.Select(p => p.LastOrDefault())
.Sum(p=> p.BetSize);
But that wont work.. Can someone help me on this?
Thanks!
Looks like this is what you want, the key takeaway being the inner query is wrapped in an outer call to Select():
var maxInvestment = TotalUserActions.GroupBy(p => p.Player)
.Select(g => g.GroupBy(x => x.RoundId)
.Select(x => x.LastOrDefault())
.Sum(x => x.BetSize))
.Max();
I do question your use of LastOrDefault() though as, since you have not specified any ordering, you may as well use FirstOrDefault() and save the hassle of skipping to the last element.
How I can make this Distinct work:
var blockIdMap = (from panelEntry in panelEntries
select new {panelEntry.BlockNo, panelEntry.BlockID})
.Distinct()
.ToDictionary(mc => mc.BlockNo , mc => mc.BlockID);
I need to have only unique entries of BlockNo with it's BlockId because I enter them to Dictionary and BlockNo should be unique.
I want just to take the first one.
var blockIdMap = panelEntries.GroupBy(pe => pe.BlockNo)
.ToDictionary(k => k.Key, v => v.First())
In this case your linq query doesn't work beacuse .Distinct() method equals panelEntry.BlockNo and panelEntry.BlockID and not only panelEntry.BlockNo. So a solution could be use MoreLinq and the method .DistinctBy():
var blockIdMap = (from panelEntry in panelEntries
select new {panelEntry.BlockNo, panelEntry.BlockID})
.DistinctBy(mc => mc.BlockNo)
.ToDictionary(mc => mc.BlockNo , mc => mc.BlockID);