Я хочу, чтобы способ обновления диапазона записей на основе предложения where в рамках сущности без использования ToList () и foreach - PullRequest
1 голос
/ 14 апреля 2020

В моем базовом приложении asp. net есть функция, которая обновляет набор записей на основе определенных критериев, которые я пишу в предложении where ... Я прочитал, что ToList () имеет плохую производительность, поэтому есть лучший и более быстрый способ, чем использование tolist и foreach ??? Это мой нынешний способ сделать это, я был бы признателен, если бы кто-то предоставил более эффективный способ

    public async Task UpdateCatalogOnTenantApproval(int tenantID)
    {
        var catalogQuery = GetQueryable();
        var catalog = await catalogQuery.Where(x => x.IdTenant == tenantID).ToListAsync();
        catalog.ForEach(c => { c.IsApprovedByAdmin = true; c.IsActive = true; });
        Context.UpdateRange(catalog);
       await Context.SaveChangesAsync(); ;
    }

Ответы [ 4 ]

1 голос
/ 14 апреля 2020

Позвольте мне объяснить вам, что вы сделали и что вы пытаетесь сделать. Вы частично правы в отношении проблем производительности, связанных с ToList и ToListAsyn c, поскольку они в основном отвечают за загрузку объектов в память и их отслеживание.

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

давайте будем более реалистичными c поговорим о вашем случае:

1 - мы предполагаем, что ваш метод требует много ресурсов (загрузка большого объема данных, интенсивно вызываемых или обоих)

2 - я вижу, что модификация слишком стати c путем обновления всех строк с помощью c.IsApprovedByAdmin = true; c.IsActive = true;

form (1) и (2), я предлагаю написать хранимую процедуру или ExexcuteSqlCammand (как Брайан Льюис предложил), что сделает это за вас

, потому что (3) хранимые процедуры, триггеры и все операции, основанные на SQL, трудно обслуживаемы и имеют большой потенциал для скрытых исключений , В вашем случае, однако, вы с меньшей вероятностью впадете в это, поскольку ваш код слишком базовый c, и вы могли бы снизить риск, создав свой запрос из динамических c элементов, таких как nameof (yourClassName, которое является именем таблицы) .YouProperty и тому подобное ...

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

Наконец, я не согласен с Расширения сторонних разработчиков, большинство из которых бесплатно предоставляются непрофессионалами и отслеживание вызванных ими исключений, являются кошмарами, а платные версии слишком дороги и не являются расширениями без исключений. Расширение 3d party больше ориентировано на сложное массовое обновление / удаление и / или огромные данные. например,

await Context.UpdateAsync(e=> new Catalog
                                  { Archived = e.LastUpdate > 
                                       DateTime.UtcNow.AddYears(-99)? false : true
                                   });
1 голос
/ 14 апреля 2020

прочитайте, что ToList () имеет плохую производительность,

Это неправильно. ToList обладает такой же высокой производительностью, как и вы, - отправьте неверный запрос, который является слишком сложным и приводит к плохому SQL, что SQL Серверу потребуется много времени для выполнения, и он медленный.

Кроме того, многие думают, что «ToList» медленный (как в: в профилировщике). Видите ли, просто запустите контекст db, возьмите туда набор сущностей, добавьте несколько предложений where - все быстро. Затем ToList и это занимает «долго» (по сравнению с остальными). Что ж, это именно тот случай, когда запрос отправляется на сервер sql;) WHEre (x => что угодно) занимает «нет времени», потому что все, что он делает, это добавляет некоторые узлы в дерево выражений, а не выполняет запрос. В основном это то, что люди путают - задержка выполнения, которая прекращается только при запросе результатов.

И в-третьих, некоторые люди, как "ToList (). Where () и жалуются на производительность. Фильтруют как можно больше, нет DB.

Все три причины, по которым люди думают, что ToList медленен - ​​но все, что он показывает, - это отсутствие понимания того, как работают LINQ и SQL.

1 голос
/ 14 апреля 2020

Entity Framework по умолчанию не обрабатывает массовые операции обновления - следовательно, ваш существующий код. Если вы действительно хотите выполнять эти массовые операции, у вас есть два варианта:

  1. Напишите SQL самостоятельно и используйте метод ExecuteSqlCommand () для его выполнения; или
  2. Посмотрите на сторонние расширения, такие как https://entityframework-extensions.net/
0 голосов
/ 14 апреля 2020

Мы можем уменьшить стоимость запроса, выбрав подмножество данных, прежде чем прикреплять EF для отслеживания, а затем обновлять. Однако это может быть просто бессмысленная микрооптимизация, которая не будет работать значительно лучше, если вы не обрабатываете огромное количество записей.

// select pk for EF to track, and the 2 fields to be modified
var catalog = await catalogQuery.Where(x => x.IdTenant == tenantID)
              .Select(x => new Catelog{x.CatelogId, x.IsApprovedByAdmin, x.IsActive }).ToListAsync();

//next we attach range here to let EF track the list
Context.AttachRange(catalog);

//perform your update as usual, this will be flagged as modified if changed
catalog.ForEach(c => { c.IsApprovedByAdmin = true; c.IsActive = true; });

//save and let EF update based on modified fields.
await Context.SaveChangesAsync(); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...