问题
I am using entity framework core 2.1, I have a database context with an accessor for a model containing a boolean field represented as a non nullable bit field in an MS SQL database. I want to construct a query that evaluates in SQL efficiently that provides me a count of all rows in the table, and those with the bit column enabled.
var groups = await this.context.Models
.AsNoTracking()
.GroupBy(i => 1)
.Select(g => new ViewModel
{
Count = g.Count(),
Revoked = g.Count(p => p.IsRevoked)
})
.ToArrayAsync();
In order to force the query to consume all rows, I use ToArray, however the group by, count and where clauses log they cannot be evaluated remotely.
Other attempts such as:
var query = await this.context.Models
.AsNoTracking()
.GroupBy(i => i.IsRevoked)
.ToArrayAsync();
Produces two groups which I can later inspect but they fail to evaluate the bit column the same.
How can I generate a single expression that produces a new object with the count of all rows and the count of the subset which have the bit field enabled?
回答1:
The first technique (group by constant) worked well in EF6. Just instead of predicate based Count
which has not direct SQL equivalent, using the conditional Sum
produced a nice GROUP BY
SQL.
Unfortunately, this doesn't translate to SQL in EF Core, even in 2.1.
Fortunately, combining it with intermediate projection produces the desired SQL translation in EF 2.1:
var counts = await this.context.Models
.Select(e => new { Revoked = e.IsRevoked ? 1 : 0 })
.GroupBy(e => 1)
.Select(g => new ViewModel
{
Count = g.Count(),
Revoked = g.Sum(e => e.Revoked)
})
.ToArrayAsync();
来源:https://stackoverflow.com/questions/50916302/groupby-query-and-bit-fields