Conversion of SQL group by to Entity Framework Lambda expression - c#

I have 3 tables A which has an ID and other fields, B which has an ID, and C has a many to many relation for the ID's in A and B
I made a query that gets the results that I need
select result.*
from
(SELECT max(A.AID) as AID
FROM A, C
where A.AID = C.AID
group by C.BID) as x, A as result
where result.AID = x.AID
and I want to convert it to a lambda expression in entity framework. But currently the query is not efficient enough. How would I make the lamda expression in EF and also make it more efficient?

If you first order your results descending by the ID you want the max of, and then GroupBy that ID in the related table, then Select the First from each grouping you should get the results you need.
var groupedResults = tempContext.A.OrderByDescending(a => a.AID
).GroupBy(group => group.C.AID).Select(group => group.FirstOrDefault());
This should return you an IQueryable of the A entity that you can then continue to modify with additional clauses if needed.

Related

Remove item from IQueryable from List

I have 2 tables in my database Products and PremiumProducts for an ASP Net application.
I retrieve products with a simple query
IQueryable<Product> query = from p in myDataContext.Products select p;
I have a List of PremiumProducts (which contains the ID of a Product). I am attempting to remove the IDs in the PremiumProducts list from the query above but not sure if there is a simple way or if i need to convert all the PremiumProducts to a Product first? I attempted this
List<PremiumProducts> premiumProducts;
query = from p in query where (premiumProducts.Contains(p.ID)) select p;
but of course this brings back all sorts of casting errors.
Is there a simple way to remove the PremiumProducts from the query above or do i need to convert the PremiumProducts to a Product, store the ID and then attempt to remove the query with these IDs?
Rather than:
query = from p in query where (premiumProducts.Contains(p.ID)) select p;
I would suggest:
query = from p in query where (!premiumProducts.Select(z => z.ID).Contains(p.ID)) select p;
The key differences:
Using ! (since you want to exclude those that are in
premiumProducts).
Using premiumProducts.Select(z => z.ID) to
ensure that the contains is against the ID not the object (just
avoiding your casting issues).

How can I set values to an object returned by Linq to Entities without using an anonymous?

I need to return an IQueryable that will be fetching data from an Entity Framework 6 database.
So far, I have a query like this:
from i in dbContext.Instruments
where i.EquipID.Equals(equip.ID)
join r in dbContext.Readings on i.ID equals r.InstrumentID into rs
from r in rs.DefaultIfEmpty()
group r by i into g
select ...;
I know I could use the following as the select portion, but then anonymous objects are returned:
select new
{
g.Key.ID,
g.Key.Name,
g.Key.InstrumentType,
g.Key.Units,
g.Key.RollOver,
g.Key.LastReading = g.OrderByDescending(x => x.DateOfReading).FirstOrDefault().Value,
g.Key.LastReadingDate = g.OrderByDescending(x => x.DateOfReading).FirstOrDefault().DateOfReading,
}
What's important are the last two properties, where values are set on-the-fly. I need the objects held by g.Key, with the properties LastReading and LastReadingDate set.
Is it possible to have a navigation property that is the result of a (sub) query, instead of an object derived by a foreign key? If so, how could I work that into my query?
Some additional thoughts...
Anonymous objects won't work because I need the actual Entity class objects later on. I can't use new Instrument() because that threw an exception (complex Entity type cannot be constructed in a LINQ to Entities query). I also cannot use something like this answer, because the query is going through Entity, and the method would not translate to an SQL statement.

How to Select subset of columns from SingleOrDefault LINQ query in EF

How can I select subset of all columns while using SingleOrDefault query? For example, following LINQ expression
var personid = ctx.persons.SingleOrDefault(p => p.login == currentLogin)?.personid;
will compile into SELECT TOP 1 * FROM ... type of query. I would like to Select() only the columns I am interested in, e.g. statement producing SELECT TOP 1 personid, myColumn FROM ... under-hood.
Please note, that the question cannot possibly be duplicate of linked question. I am interested in context of Single/SingleOrDefault not generic solution for LINQ. Chaining .SingleOrDefault() with .Select() is not possible for apparent reasons: Single<T>returns single object of type T (or throws) which clearly does not implement IEnumerable<T> and cannot be Select()ed upon.
var personid = ctx.persons
.Where(p => p.login == currentLogin)
.Select(p => new {Prop = p.Column, personid = p.id})
.SingleOrDefault()?.personid;
Would probably work.

Join vs Navigation property for sub lists in Entity Framework

I have a sql statement like this:
DECLARE #destinations table(destinationId int)
INSERT INTO #destinations
VALUES (414),(416)
SELECT *
FROM GroupOrder grp (NOLOCK)
JOIN DestinationGroupItem destItem (NOLOCK)
ON destItem.GroupOrderId = grp.GroupOrderId
JOIN #destinations dests
ON destItem.DestinationId = dests.destinationId
WHERE OrderId = 5662
I am using entity framework and I am having a hard time getting this query into Linq. (The only reason I wrote the query above was to help me conceptualize what I was looking for.)
I have an IQueryable of GroupOrder entities and a List of integers that are my destinations.
After looking at this I realize that I can probably just do two joins (like my SQL query) and get to what I want.
But it seems a bit odd to do that because a GroupOrder object already has a list of DestinationGroupItem objects on it.
I am a bit confused how to use the Navigation property on the GroupOrder when I have an IQueryable listing of GroupOrders.
Also, if possible, I would like to do this in one trip to the database. (I think I could do a few foreach loops to get this done, but it would not be as efficient as a single IQueryable run to the database.)
NOTE: I prefer fluent linq syntax over the query linq syntax. But beggars can't be choosers so I will take whatever I can get.
If you already have the DestinationGroupItem as a Navigation-property, then you already have your SQL-JOIN equivalent - example. Load the related entities with Include. Use List's Contains extension method to see if the desired DestinationId(s) is(are) hit:
var destinations = new List<int> { 414, 416 };
var query = from order in GroupOrder.Include(o => o.DestinationGroupItem) // this is the join via the navigation property
where order.OrderId == 5662 && destinations.Contain(order.DestinationGroupItem.DestinationId)
select order;
// OR
var query = dataContext.GroupOrder
.Include(o => o.DestinationGroupItem)
.Where(order => order.OrderId == 5662 && destinations.Contain(order.DestinationGroupItem.DestinationId));

Convert query from SQL to LINQ

I need to convert this SQL query to LINQ:
SELECT COUNT(result1.Id) AS total,
result1.OccurrenceDate,
result1.Path,
result1.Message,
result1.StackTrace
FROM (SELECT * FROM tbllog ORDER BY OccurrenceDate DESC) AS result1
GROUP BY result1.Path, result1.Message ORDER BY total DESC
But I'm not getting success. I've tried in so many ways, nothing works.
Some help?
Create a linq query out of the following:
SELECT * FROM tbllog ORDER BY OccurrenceDate DESC AS result1
GROUP BY result1.Path, result1.Message ORDER BY total DESC
Once that is done, write some linq to get your counts.
var results = _dbContext.tbllog
.GroupBy( t => new { t.Path, t.Message })
.Select( g => new
{
Total = g.Count(),
Path = g.Key.Path,
Message = g.Key.Message
}).OrderBy(p => p.Total);
It is worth to mention that your sql query is invalid because the properties OccurrenceDate and StackTrace is not in the GROUP BY clause nor with in an aggregate function, therefore it is invalid query. The same with the LINQ query. You should determine what you want to do with them. Either include them in the group by or use an aggregate function to select the appropriate value for each group.
I don't know what the context is for your question, but if you don't need to modify the query such that it executes with additional parameters, I would highly recommend executing the query as SQL. This is supported on all the ORMs that I am aware of (Entity Framework, NHiberate, LINQ to SQL, etc).
Erick

Categories

Resources