Замените использование нежелательного foreach новым запросом в EF - PullRequest
0 голосов
/ 30 января 2019

У меня есть таблица, как показано ниже

Employee
-------------------
id    role 
1      a
2      a
3      b
4      c
5      b
----------------------

У меня есть фильтры ids {1,3,5} and roles {a,b}

Поэтому мне нужно получить строки, которые имеют id=1 and role=a , id=2 and role=b , id=3 and role=a, id=3 and role=b etc...

Так в основном id * roles, что мне нужно получить из базы данных.

Текущий код, используемый в моем проекте, выглядит следующим образом:

foreach (int role in roles)
                    {

                        foreach (int id in ids)
                        {
//get the data using id and role and append to a list 
}
}

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

var itemsTobeDeleted = context.TableName.Where
                       (
                        item =>
                            obj.ids.Contains(item.Id) &&
                            obj.roles.Contains(item.Role)
                        ).ToList();

Мой вопрос заключается в том, будет ли этот новый запрос давать тот же результат, что и для каждого запроса?Если да, то как насчет производительности?

Или у нас есть лучший способ сделать то же самое?

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Да, ваше второе решение более эффективно!

Вы используете DbContext для доступа к вашей таблице.Видимо эта таблица находится в базе данных.Системы управления базами данных чрезвычайно оптимизированы для запросов данных.

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

Ваш метод foreach будет выполнять один запрос на комбинацию [role, id].Это очень неэффективно.Ваш второй метод будет принимать только один запрос и возвращать только одну результирующую последовательность.Это намного эффективнее.

Добавление:
Иван Стоев показал мне, что приведенный ниже метод не работает: в отличие от IEnumerable, IQueryable.Contains может обрабатывать толькопримитивные типы.Следовательно, содержимое Contains ниже не будет работать.

Поэтому следующее не работает как IQueryable.
Этот запрос может быть немного оптимизирован: позвольте вашему процессу создать последовательность требуемой [роли,id] комбинаций и запросите в базе данных все TableNames, которые соответствуют этой комбинации.

class RoleIdCombination
{
    public char Role {get; set;}
    public int Id {get; set;}
}

// let your process create the requested RoleIdCombinations:
var roleIdCombinations = CreateRoleIdCombinations(roles, ids);

// do only one query:
var result = dbContext.TableNames
    .Select(tableName => new
    {
         // for easier equality check: make a RoleIdCombination:
         RoleIdCombination = new RoleIdCombination
         {
              Role = tableName.Role,
              Id = tableName.Id,
         }
         // remember the original item
         TableName = tableName,
     })
    .Where(item => roleIdCombinations.Contains(item.RoleIdCombination));

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

Функция CreateRoleIdCombinations:

IEnumerable<RoleIdCombination> CreateRoleIdCombinations(
    IEnumerable<char> roles,
    IEnumerable<int> ids)
{
     foreach (var role in roles)
     {
         foreach (var id in ids)
         {
              yield return new RoleIdCombination
              {
                  Role = role,
                  Id = id,
              };
         }
     }
}

Для этого нам нужны (количество ролей * количество идентификаторов) перечисления.Я ожидаю, что это будет намного меньше, чем количество элементов в вашей таблице, в конце концов, вы не будете удалять половину таблицы каждый раз, не так ли?

0 голосов
/ 30 января 2019

Если вы измените свою коллекцию на установите , тогда Содержит стоит O (1), поэтому ожидается более высокая производительность, чем List.Contains (O (n)).

HashSet<int> ids= new HashSet<int>{ 1,3,5 };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...