ef group by columns order issue? - c#

Ok, imagine that I have EF 6.1.3 and database first model (stored in edmx file) that contains an entity named Product.
That entity have 4 columns, for example: Id (int), Name {string), Code (string), Rank (int). The columns are stored in that order as I described and you can see that in a model browser.
Then i'm writing a query like this:
var list = mycontext.Products
.Where(x => x.Id < 10)
.GroupBy(x => new { x.Code, x.Name })
.Select(x=> new { x.Key.Code, x.Key.Name, MaxRank = x.Max(z => z.Rank) })
.ToList();
As you can see, I used an another columns order in my group by clause (Code column, then Name column).
But in SQL query I have such query text:
....
GROUP BY
[Extent1].[Name]
, [Extent1].[Code]
....
The columns in group by clause always ordered in same order which they have in a edmx file.
It just a sample, but that situation always break my query plans, cause sql starting to use wrong indexes and etc.
Anybody know how can I fix that?
without sort
with sort

Related

Problem with converting raw SQL to Entity Framework, order by, count

I have a trouble with converting this SQL query to Entity Framework:
SELECT Products.Name, COUNT(*)
FROM OrdersProducts
JOIN Products on OrdersProducts.ProductId = Products.Id
GROUP BY Products.Id
ORDER BY COUNT(*) DESC
Tried hard but with no results. I don't have any idea how to make it work.
If your entity model relations allows it, you could try something like that :
dbcontext.Products
.Include(orders=> orders.OrderProducts)
.Select(x => new { Name = x.Name, Count = x.OrderProducts.Count })
.OrderByDescending(x => x.Count)
.ToList();
I think the SQL generated by EF could be near of your query...

Cannot include child table after GroupBy

I have two related tables:
OrderHeader
Id
Truck_name
Group
OrderItem
Id
OrderID
Location
Read
OrderItem contains column OrderHeaderId (foreign key relationship).
My WebService has to select specific Order with orderItems and return it(after some parsing) to client. I have to use eager loading because of important data in OrderItem.My database query needs to load first not finished (Status IN 1402,1403 AND Read=0) order. So:
context.Configuration.LazyLoadingEnabled = false;
var query = context.OrderHeader
.Where(o=> new[] { 1402, 1403 }.Contains(o.Status) && o.OrderItem.Any(g => g.Read == 0))
.OrderBy(o => o.Id)
.GroupBy(g => g.Group)
.FirstOrDefault()
.AsQueryable()
.Include("OrderItem");
I use GroupBy to take first not finished Group and every time it returns me an empty OrderItem table. Why? How to include child table after GroupBy statement?

Add ROW_NUMBER to a LINQ query for specific Entity?

I need an EF query to get the row number of a specific entity.
I've looked at this, and this.
Currently I have it working in this way:
private DbContext Context;
public int GetRowNumberQuery<TEntity>(int entityId)
{
var allEntities = this.Context.Set<TEntity>().ToList();
return allEntities
.Select((entity, index) => new { Index = index, Entity = entity })
.Where(x => x.Entity.Id == entityId)
.Select(x => x.Index)
.SingleOrDefault();
}
Obviously, this is very inefficient as it gets a list of all entities before selecting the index. If I remove the .ToList() in the first line, making the whole thing a LINQ query, it fails at the first Select with NotSupportedException saying:
LINQ to Entities does not recognize the method
'System.Linq.IQueryable1[<>f__AnonymousType12[System.Int32,MyEntityType]]
Select[MyEntityType,<>f__AnonymousType12](System.Linq.IQueryable1[MyEntityType],
System.Linq.Expressions.Expression1[System.Func3[MyEntityType,System.Int32,<>f__AnonymousType1`2[System.Int32,MyEntityType]]])'
method, and this method cannot be translated into a store expression.
Can you please tell me how to get the ROW_NUMBER of a specific entity?
Or is it impossible like this pretty old question suggests?
A) Entity Framework doesn't support ROW_NUMBER() (the examples given use EF to generate a query and then "attach" a number to each returned row client side, starting from 1 and going to n if there are n rows)
B) Even in TSQL the query would be complex:
SELECT TOP 1 ROW_NUMBER() OVER (ORDER BY ID) RN FROM SomeTable WHERE ID = 100
would return NULL if there are no rows or 1 if there is a row with ID 100
You would need something like
SELECT B.RN
FROM
(SELECT ID, ROW_NUMBER() OVER (ORDER BY ID) RN
FROM SomeTable) B
WHERE B.ID = 100
C) Clearly you can create a view/stored procedure that uses ROW_NUMBERand call it from EF

Linq-To-Entities 'Contains' clause 1-many relationship

Consider a (simplified) table structure like this:
[USERS]
EMPID
NAME
[APPOINTMENTS]
(FK_APPT_USER) EMPID
APPTTYPEID
COMPLETE
Each user can have 0..* appointments, each of which can be one of many APPTYPEID's, and can either be complete or not complete.
I want to filter the result set of a IQueryable[USER] query such that it only includes USERS who have an appt of some typeID (say 1) and where the COMPLETE field is in a list of values. I'm doing this as part of a gridview filter that allows users to select either to show only completed or not completed users for particular appointment types.
List<string> vals = new List<string> {"Y","N"}
//maybe the user has only selected Y so the above list only contains 1 element
var qry = ctx.USER.Where(x=> vals.Contains( ? ));
//bind etc
This is really easy to do if the values I'm comparing against the list are in a 1-1 relationship with the USER object, for example:
var qry = ctx.USER.Where(x=> vals.Contains(x.NAME));
But I don't understand how to do it with a 1-many relationship like with my appointments table, it's getting me all brain-tied trying to conceptualize the entity sql for it. Can anybody explain how to do this?
qry = ctx.USER.Where(u => u.APPOINTMENTS
.Where(a => a.APPTYPEID == 1)
.Any(a => vals.Contains(a.COMPLETE)));
UPDATE (added returning those users, which do not have appointments at all)
qry = ctx.USER.Where(u =>
!u.APPOINTMENTS.Any() ||
u.APPOINTMENTS.Any(a => a.APPTYPEID == 1 && vals.Contains(a.COMPLETE)));

How do i get the top 5 items in a database based on the occurence of a particluar field?

Using Ado.Net Entity framework, I am trying to get the 'top 3' items in a table based on the amount of times they appear in a table.
For example:
Table:
basket_to_product_id | basket_id | product_id
I want to see how many times product_id occurs, and would like to return the top 3 product_ids that occur the most frequently.
I'm stuck at:
List<BasketToProduct> btplist = entities.BasketToProduct. ..........?
Something like this should work (of course I do not know the actual names of your properties):
IEnumerable<int> top3ProductIds = (from btp in entities.BasketToProduct
group btp by btp.ProductId into g
orderby g.Count() descending
select g.Key).Take(3);
You could try to use a LINQ query on the table.
Try this:
var query = entities.BasketToProduct
.GroupBy(btp => btp.ProductID)
.Select(g => ProductID = g.Key, Count = g.Count())
.OrderBy(g => g.Count)
.Take(3);
It'll get you the top three ProductIDs and their associated counts.

Categories