2016-09-17 5 views
2

Я работаю над небольшим проектом ASP.NET Core для пометки изображений с использованием Entity Framework Core в базе данных Sqlite, в основном для обучения. Существуют две таблицы (и POCOs), теги и изображения, где несколько тегов связаны с каждым изображением. Я пытаюсь получить количество всех изображений, у которых есть теги, связанные с ними.EF Core custom count query

В простом SQL я бы написал SELECT COUNT(DISTINCT ImageId) FROM Tags, чтобы получить счет, а в LINQ я придумал _context.Tags.Select(t => t.Image).Distinct().Count(). Но этот запрос LINQ приводит к тому, что EF-Core присоединяется к двум таблицам, возвращает все строки, а затем выполняет код Distinct и Count.

Я попытался сделать _context.Tags.FromSql("SELECT COUNT(DISTINCT ImageId) FROM Tags"), но поскольку этот запрос возвращает только счет, вызванный сбоем, поскольку EF не может сопоставить результат с тегом. Я также пытался использовать _context.Database.FromSql<int>, но не смог найти на нем никакой реальной документации, и для этого не похоже IntelliSense.

То, что я сделал сейчас это то, что подробно описано в разделе «ADO.NET» этого 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); 
    } 
} 

Но это то, что лучший способ идти о получении счета эффективно?


Edit: Вот запрос, который 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 из документации Core Entity Framework.

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().

+0

Я добавил запрос, который отображается в Отладочном выходе в моем Вопросе. Я только когда-либо перешагивал вызов LINQ, никогда в нее не попадал. Но я создам журнал и посмотрю, что будет написано во время работы в Release. –

+0

Запуск в отладке или выпуске не должен иметь никакого значения, но стоит попробовать. – LittleDebugger

+0

Странно, что запрос включает в себя заказ. Каков результат, если вы удалите выделение? _context.Tags.Distinct(). Count() – LittleDebugger