-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GroupBy() Min() Limitations #29455
Comments
Can you run example 2 as SQL?? |
Can't in MS SQL Server. But in MySQL I hardly remember it was working. |
There are 3 approaches at the top of my head to tackle this the first approach is doing a IEnumerable<Agent> AgentList = _db.Agents
.GroupBy(fields => fields.WorkingArea)
.Select(x => x.MinBy(i => i.Commission))
.Select(fields => new Agent
{
WorkingArea = fields.WorkingArea,
Commission = fields.Commission,
PhoneNo = fields.PhoneNo,
}); unfortunately, the approach above won't work at the moment since EF Core can't translate second approach which I feel EF Core should be able to translate to SQL involves doing an IEnumerable<Agent> AgentList = _db.Agents
.GroupBy(fields => fields.WorkingArea)
.Select(x => x.OrderBy(i => i.Commission).FirstOrDefault())
.Select(fields => new Agent
{
WorkingArea = fields.WorkingArea,
Commission = fields.Commission,
PhoneNo = fields.PhoneNo,
}); third approach involves applying an accumulator function (Aggregate) over a sequence, I have no idea if EF Core can translate this to IEnumerable<Agent> AgentList = _db.Agents
.GroupBy(fields => fields.WorkingArea)
.Select(x => x.Aggregate((a, b) => a.Commission < b.Commission ? a : b))
.Select(fields => new Agent
{
WorkingArea = fields.WorkingArea,
Commission = fields.Commission,
PhoneNo = fields.PhoneNo,
}); Personally, I think you should go with the second approach as EF Core has a better chance at translating that to |
@Xor-el none of your suggestions actually translate with EF - it's a good idea to test code suggestions before posting them.
To get all working areas with the minimal commission for each working area (without the phone number), simply project out the group key as follows: var agents = await ctx.Agents
.GroupBy(agent => agent.WorkingArea)
.Select(g => new Agent
{
WorkingArea = g.Key,
Commission = g.Min(fields => fields.Commission),
});
This is a very different requirement. Re the SQL you say you're looking for: SELECT WorkingArea, MIN(Commission), PhoneNo
FROM agents
GROUP BY WorkingArea As written above, that doesn't work on most databases, since you can't project a column without an aggregate function in a query containing GROUP BY. You say that this works on MySQL; but which phone number does it return exactly? I'm pretty sure there's no guarantee it would return the phone number for the agent with the minimal commission (there's no connection between the two projections). #25566 tracks EF translating MinBy, which as @Xor-el wrote would be appropriate here. Based on suggestions in that issue, here's a query that probably does what you want: var agents = await ctx.Agents
// Get the agent with the lowest commission for each working area
.GroupBy(agent => agent.WorkingArea)
.Select(g => new { WorkingArea = g.Key, Commission = g.Min(fields => fields.Commission) })
// Join back to the agents table to get the top agent Id for each { WorkingArea, MinCommission } pair
.Join(ctx.Agents, wa => wa, agent => new { agent.WorkingArea, agent.Commission }, (wa, agent) => agent)
.GroupBy(agent => new { agent.WorkingArea, agent.Commission })
.Select(group => new
{
group.Key.WorkingArea,
MinCommission = group.Key.Commission,
AgentPhoneNo = group.Max(a => a.PhoneNo)
})
.ToListAsync(); This generates the following SQL: SELECT [a0].[WorkingArea], [a0].[Commission] AS [MinCommission], MAX([a0].[PhoneNo]) AS [AgentPhoneNo]
FROM (
SELECT [a].[WorkingArea], MIN([a].[Commission]) AS [Commission]
FROM [Agents] AS [a]
GROUP BY [a].[WorkingArea]
) AS [t]
INNER JOIN [Agents] AS [a0] ON ([t].[WorkingArea] = [a0].[WorkingArea] OR ([t].[WorkingArea] IS NULL AND [a0].[WorkingArea] IS NULL)) AND [t].[Commission] = [a0].[Commission]
GROUP BY [a0].[WorkingArea], [a0].[Commission] The above returns the phone number for a random agent which has the minimum commission for a working area. |
Duplicate of #25566 |
Let's say my database table Agents is the following,
What I exactly need to query is as the following(in SQL for better understanding).
And its result is:-
How can I do the same with .NET Entity Framework MVC?
I tried the following. But it gave me only the MIN(COMMISSION) row.
1. How can I do the equivalent to the sql query above, with .NET Entity Framework?
2. What if I want add also the PhoneNo column to the result? like
The text was updated successfully, but these errors were encountered: