Как эффективно подсчитать количество элементов в таблице с помощью EntityFramework? - PullRequest
0 голосов
/ 17 января 2020

У меня есть проект C#, в котором несколько элементов хранятся в разных таблицах, например, для подсчета количества элементов в таблице я делаю что-то похожее на следующее:

public int getLengthListProducts(int idCompany)
{
  try
  {
      using (var context = new ccoFinalEntities())
      {
        return context.products.Where(p => true == p.status && idCompany == p.idCompany).ToList().Count;
      }
  }
  catch
  {
    return -1;
  }
}

До сих пор это работало очень хорошо, но когда количество начинает составлять 1000 единиц, на некоторых компьютерах для получения этого числа требуется некоторое время.

Я подозреваю, что context.products помещает все элементы в ОЗУ, а затем начинает извлекать и подсчитывать те из них, которые соответствуют следующим условиям, и поэтому приложение заморожено до завершения подсчета.

Мой вопрос : Есть ли способ сделать это лучше?

Например, я подумал, что мне следует прибегнуть непосредственно к SQL инструкциям вместо использования EntityFramework для получения этого числа, но я не знаю, будет ли это хорошая идея, или если есть более эффективный способ с EntityFramework.

Любые комментарии или предложения приветствуются.

Ответы [ 3 ]

6 голосов
/ 17 января 2020
context.products.Where(p => true == p.status && idCompany == p.idCompany).ToList().Count;

В этом запросе Linq ToList() сгенерирует запрос SQL:

SELECT ...
FROM Products
WHERE status = 1 and idCompagny = @idCompany

Этот запрос выполняется в вашей базе данных и может вернуть много строк. Все элементы загружаются в память клиента в. Net Коллекция и Count возвращают конечный результат.

С Entity Framework вы можете использовать агрегированный запрос Linq (Count, Sum, Avg, ...):

https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/linq/aggregate-queries

Пример:

context.products.Where(p => true == p.status && idCompany == p.idCompany).Count();

Count() сгенерирует запрос SQL:

SELECT COUNT(*)
FROM Products
WHERE status = 1 and idCompagny = @idCompany

Запрос выполняется в вашей базе данных и возвращает скалярный результат.

1 голос
/ 17 января 2020
context.products.Count(p => p.status == true && idCompany == p.idCompany);

или

context.products.Where(p => p.idCompany == idCompany)
                .Count(p => p.status == true);

(для удобства чтения)

будет достаточно.

0 голосов
/ 17 января 2020

Для SQL -Server вы можете сделать это

   string cmd = @"SELECT
        t.NAME AS TableName,
        s.Name AS SchemaName,
        p.rows AS RowCounts,
        SUM(a.total_pages) * 8 AS TotalSpaceKB,
        SUM(a.used_pages) * 8 AS UsedSpaceKB,
        (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB
    FROM
        sys.tables t
    INNER JOIN
        sys.indexes i ON t.OBJECT_ID = i.object_id
    INNER JOIN
        sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
    INNER JOIN
        sys.allocation_units a ON p.partition_id = a.container_id
    LEFT OUTER JOIN
        sys.schemas s ON t.schema_id = s.schema_id
    WHERE
        t.NAME NOT LIKE 'dt%'
        AND t.is_ms_shipped = 0
        AND i.OBJECT_ID > 255
    GROUP BY
        t.Name, s.Name, p.Rows
    "
    db.Database.SqlQuery(cmd).ToList<Statistic>();

с

    public class Statistic
    {
        public string TableName { get; set; }
        public string SchemaName { get; set; }
        public long RowCounts { get; set; }
        public long TotalSpaceKB { get; set; }
        public long UsedSpaceKB { get; set; }
        public long UnusedSpaceKB { get; set; }
    }

Затем вы получите довольно быстрый обзор всех ваших таблиц, включая размер в памяти.

Я знаю, что жестко запрограммированный SQL не является предпочтительным, но поскольку он относится только к системным таблицам, и поэтому, как вы можете предположить, они никогда не меняются, это приемлемо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...