2016-09-17 131 views
2

我工作的一个小ASP.NET核心项目SQLite数据库使用实体框架的核心标记图像,主要只是为了学习。有两个表(和POCO),标签和图像,其中多个标签与每个图像相关。我试图计算所有具有与它们关联的标签的图像。EF核心的定制数查询

在普通的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>,但无法找到任何真实文档,并且似乎没有IntelliSense。

我已经完蛋了,现在是什么详述此blog post from Eric Anderson的“ADO.NET”一节中:

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" 

回答

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"); 
0

你的代码原有线路应已经完成了你想要的。它也将建议通过内联SQL。

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

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

一种检查实际查询的方法,不用破坏运行代码,通过使用实体框架核心文档中的MyLoggerProvider

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

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

以下日志消息使用网站上例的数据库表的独特()和一个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(),而不是选择()。

+0

我已将调试输出中显示的查询添加到我的问题中。我只是跨过了LINQ调用,从来没有进入它。但是我会设置日志记录并查看在Release中运行时写入的内容。 –

+0

在调试或发布中运行应该没有什么区别,但它值得一试。 – LittleDebugger

+0

奇怪的是,查询包含一个order by。如果您删除了选择,结果如何? _context.Tags.Distinct()。Count() – LittleDebugger