How to convert this SQL statement to Linq for C# - c#

I am trying to convert my simple SQL statement into Linq format for my C# application but I always seem to struggle making the conversion. I downloaded linqpad and have been playing around with it but I'm still having issues with the proper format.
My SQL statement:
SELECT distinct PictureCity, PictureState
FROM Website_Gallery
GROUP BY PictureCity, PictureState, PictureDate
ORDER BY PictureCity, PictureState
The results are ordered by PictureCity and look like this:
Abington MA
Acton MA
Acushnet MA
Agawam MA
Andover MA
Arlington MA
Arlington TX
Ashby MA
Ashland MA
What I have so far in my C# application which I can't seem to get to work. (I suck at linq).
var Results = _context.Website_Gallery
.(g => g.PictureCity, g => g.PictureState).AsEnumerable()
.Select g
.GroupBy(g => g)

Seems like all you need is
var results = _context.Website_Gallery
.OrderBy(x => x.PictureCity)
.ThenBy(x => x.PictureState)
.Select(x => new { x.PictureCity, x.PictureState })
.Distinct();
that would be equivalent to the following SQL
SELECT distinct PictureCity, PictureState
FROM Website_Gallery
ORDER BY PictureCity, PictureState
because what you had did not need the group by
Note you can then either iterate that result in a foreach or tack a ToList to the end to materialize the query into memory.

SQL
SELECT distinct PictureCity, PictureState
FROM Website_Gallery
ORDER BY PictureCity, PictureState
Linq
var Results = _context.Website_Gallery
.Select(g => new { g.PictureCity, g.PictureState })
.Orderby(p => p.PictureCity).ThenBy(p => p.PictureState)
.Distinct().ToList();
Or you can also do this
var Results = _context.Website_Gallery
.GroupBy(x => new { PictureCity = x.PictureCity, PictureState = x.PictureState })
.Select(g => new { g.Key.PictureCity, g.Key.PictureState }).Orderby(p => p.PictureCity).ThenBy(p => p.PictureState)
.ToList();

Related

How to write linq query for this sql statement

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.

linq is taking long to order by datediff

I am trying to convert the following sql query to linq. The sql query is taking one second to run, but the linq is taking about 10 seconds
to return the results. Could anyone please let me know how can I reduce the time on linq query
select datediff(mm, min(QueuedTime), max(QueuedTime)), SequencingQueue
from tbl_AS_MessageQueue with (nolock)
group by SequencingQueue
order by datediff(mm, min(QueuedTime), max(QueuedTime)) desc
var longRunningQueries = context.TblMessageQueues.GroupBy(x => x.SequencingQueue).Select(g => new TblMessageQueueDto
{
DateDiff = DbFunctions.DiffMonths(g.Min(x => x.QueuedTime),
g.Max(x => x.QueuedTime)),
SequencingQueue = g.Key
}).OrderByDescending(a => a.DateDiff).ToList();
Rewrite your query to select DTO after ordering:
var longRunningQueries = context.TblMessageQueues
.GroupBy(x => x.SequencingQueue)
.Select(g => new {
DateDiff = DbFunctions.DiffMonths(g.Min(x => x.QueuedTime), g.Max(x => x.QueuedTime)),
SequencingQueue = g.Key
}).OrderByDescending(a => a.DateDiff)
.Select(t => new TblMessageQueueDto {
DateDiff = t.DateDiff,
SequencingQueue = t.SequencingQueue
}).ToList();

How to create query of queries using LINQ?

I'm trying to convert query of queries used in ColdFusion to LINQ and C#. The data come from data files, rather than from the database.
I converted the first query, but have no clue as to
how to use it to query the second query.
how to include count(PDate) as DayCount in the second query.
Below is the code using query of queries in ColdFusion:
First query
<cfquery name="qSorted" dbtype = "query">
SELECT OA, CD,PDate,
FROM dataQuery
GROUP BY CD,OA,PDate,
</cfquery>
Second query
<cfquery name="qDayCount" dbtype = "query">
SELECT OA, CD, count(PDate) as DayCount
FROM qSorted // qSorted is from the first query.
GROUP BY
OA, CD
ORDER BY
OA, CD
</cfquery>
Here's the first converted LINQ query, and it works fine:
var Rows = allData.SelectMany(u => u._rows.Select(t => new
{
OA = t[4],
CD = t[5],
PDate = t[0]
}))
.GroupBy(x => new { x.CD, x.OA, x.PDate })
.Select(g => new
{
g.Key.OA,
g.Key.CD,
g.Key.PDate
})
.ToList();
Here's the pseudo-code for the second LINQ query, which I need your assistance:
var RowsDayCount = Rows //Is this correct? If not, how to do it?
.GroupBy(x => new { x.OA, x.PDate, x.CD, })
.Select(g => new
{
g.Key.OA,
g.Key.CD,
g.Key.PDate,//PDate should be PDate.Distinct().Count() asDayCount
// See DayCount in cfquery name="qDayCount" above.
})
.OrderBy(u => u.OA)
.ThenBy(u => u.CD)
.ToList();
Your second query origionally wasn't grouping on PDate, but your translation is. That's wrong. If you want to count the number of PDates for each OA/CD pair, you need to not group on PDate. Once you've made that change, you can modify the Select to pull out all of the PDate values from the group, and count the distinct values.
.GroupBy(x => new { x.OA, x.CD, })
.Select(g => new
{
g.Key.OA,
g.Key.CD,
DayCount = g.Select(item => item.PDate).Distinct().Count(),
})

Distinct in Linq query

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);

EF Linq to Entities Query with groupby sum and min

I am trying to make a Linq to Entities Query working but I can't figure it out.
This is my my SQL query which is working fine:
SELECT SUM(ca.PointValue) as Points, ua.UserFBID, MIN(ua.[Date]) as FirstDate
FROM [LeaderOfNow].[dbo].[QuestionAnswer] ca
inner join [LeaderOfNow].[dbo].[LONUserAnswers] ua
on ca.Id = ua.AnswerId
group by ua.UserFBID
order by Points desc, FirstDate asc
An so far my best attempt is:
var leaders = db.LONUserAnswers
.GroupBy(a => a.UserFBID)
.Select(a =>
new
{
FBID = a.Key,
CurrentPoints = a.Select(v => v.QuestionAnswer.PointValue).Sum(),
FirstAnswered = a.Min(v => v.Date)
})
.OrderByDescending(a => a.CurrentPoints)
.OrderBy(a => a.FirstAnswered)
.Take(10)
.ToList();
However that renders a mess of sql and only respect the first order by and not the second, which I need to work. Any suggestions on what am I doing wrong? Thank you for the help.
When you chain OrderBy-Functions you have to use ThenBy() or ThenDescendingBy() for the latter.

Categories