EF Core custom count query

我只是一个虾纸丫 提交于 2019-12-11 02:26:26

问题


I'm working on a small ASP.NET Core project for tagging images using Entity Framework Core on a Sqlite database, mainly just for learning. There are two tables (and POCOs), Tags and Images, where multiple tags are related to each image. I'm trying to get a count of all Images that have tags associated with them.

In plain SQL I'd write SELECT COUNT(DISTINCT ImageId) FROM Tags to get the count, and in LINQ I came up with _context.Tags.Select(t => t.Image).Distinct().Count(). But that LINQ query appears to cause EF-Core to join the two tables, return all of the rows, and then do the Distinct and Count in code.

I tried to do _context.Tags.FromSql("SELECT COUNT(DISTINCT ImageId) FROM Tags"), but because that query only returns the count the call fails because EF can't map the result to a Tag. I also tried to use _context.Database.FromSql<int>, but wasn't able to find any real documentation on it and there doesn't seem to be IntelliSense for it.

What I have done for now is what's detailed in the "ADO.NET" section of this blog post from Eric Anderson:

int count;
using (var connection = _context.Database.GetDbConnection())
{
    connection.Open();

    using (var command = connection.CreateCommand())
    {
        command.CommandText = "SELECT COUNT(DISTINCT ImageId) FROM Tags";
        string result = command.ExecuteScalar().ToString();

        int.TryParse(result, out count);
    }
}

But is that the best way to go about getting the count efficiently?


Edit: Here's the query that EF is putting in the Debug output:

SELECT "t"."TagId", "t"."Content", "t"."ImageId", "t.Image"."ImageId", "t.Image"."FileName", "t.Image"."Path", "t.Image"."Url"
FROM "Tags" AS "t"
LEFT JOIN "Images" AS "t.Image" ON "t"."ImageId" = "t.Image"."ImageId"
ORDER BY "t"."ImageId"

回答1:


As of now, you can't define an ad-hoc result. Good news is that it's currently on the backlog: https://github.com/aspnet/EntityFramework/issues/1862

In the meantime, here's an extension method that would work:

public static int IntFromSQL(this ApplicationDbContext context, string sql )
{
    int count;
    using (var connection = context.Database.GetDbConnection())
    {
        connection.Open();

        using (var command = connection.CreateCommand())
        {
            command.CommandText = sql;
            string result = command.ExecuteScalar().ToString();

            int.TryParse(result, out count);
        }
    }
    return count;
}

Usage:

int result = _context.IntFromSQL("SELECT COUNT(DISTINCT ImageId) FROM Tags");



回答2:


Your original line of code should have done exactly what you wanted. It would also be recommended over inline SQL.

_context.Tags.Select(t => t.Image).Distinct().Count()

Are you sure that this called the database for the two tables and then queried them in memory? If you observed this behaviour while debugging then it's possible that your inspection caused the IQueryable to enumerate which would call the database using a different query than it would have otherwise.

A way to check the actual query, without breaking into the running code, is by using the MyLoggerProvider from the Entity Framework Core documentation.

https://docs.efproject.net/en/latest/miscellaneous/logging.html?highlight=logging

Once the logger is registered in the code then any SQL query ran against the server will be displayed in the console window and/or in the file c:\temp\log.txt.

The following log message was generated when using a Distinct() and a Count() on the database tables of the website example.

SELECT COUNT(*)
FROM (
SELECT DISTINCT [a.Blog].[BlogId], [a.Blog].[Url]
FROM [Posts] AS [a]
INNER JOIN [Blogs] AS [a.Blog] ON [a].[BlogId] = [a.Blog].[BlogId]
) AS [t]Closing connection to database '***' on server 'tcp:**************'.

Finally, since you do not need any of the properties on the t.Image then it seems that you should be using a Where() rather than a Select().



来源:https://stackoverflow.com/questions/39543221/ef-core-custom-count-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!