EF Core自定义计数查询

时间:2016-09-17 05:35:52

标签: c# linq asp.net-core entity-framework-core

我正在开发一个小型ASP.NET核心项目,用于在Sqlite数据库上使用Entity Framework Core标记图像,主要用于学习。有两个表(和POCO),标签和图像,其中多个标签与每个图像相关。我试图计算所有带有标签的图像。

在普通的SQL中,我写SELECT COUNT(DISTINCT ImageId) FROM Tags来计算,在LINQ中,我提出了_context.Tags.Select(t => t.Image).Distinct().Count()。但是LINQ查询似乎会导致EF-Core加入这两个表,返回所有行,然后在代码中执行DistinctCount

我尝试执行_context.Tags.FromSql("SELECT COUNT(DISTINCT ImageId) FROM Tags"),但由于该查询仅返回计数,因此调用失败,因为EF无法将结果映射到标记。我也尝试使用_context.Database.FromSql<int>,但无法在其上找到任何真实的文档,并且它似乎并不是智能感知。

我现在所做的是&#34; ADO.NET&#34;这段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);
    }
}

但这是获得有效计数的最好方法吗?

编辑:这是EF在调试输出中放置的查询:

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"

2 个答案:

答案 0 :(得分:3)

截至目前,您无法定义临时结果。 好消息是,它目前正在积压:https://github.com/aspnet/EntityFramework/issues/1862

与此同时,这是一种可行的扩展方法:

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;
}

用法:

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

答案 1 :(得分:0)

您原来的代码行应该完全符合您的要求。它也建议使用内联SQL。

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

您确定这称为两个表的数据库,然后在内存中查询它们吗?如果您在调试时发现了这种行为,那么您的检查可能会导致IQueryable枚举使用不同于其他查询的查询来调用数据库。

检查实际查询的方法是使用Entity Framework Core文档中的 MyLoggerProvider ,而不会破坏正在运行的代码。

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

在代码中注册记录器后,对服务器运行的任何SQL查询都将显示在控制台窗口和/或文件c:\ temp \ log.txt中。

在网站示例的数据库表上使用Distinct()和Count()时,会生成以下日志消息。

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:**************'.

最后,因为你不需要t.Image上的任何属性,所以你似乎应该使用Where()而不是Select()。