#entity-framework #linq
#entity-framework #linq
Вопрос:
У меня есть запрос LINQ
var age = new int[]{1,2,3};
dbContext.TA.WHERE(x=> age.Contains( x.age)).ToList()
В онлайн-статье # 11 (https://medium.com/swlh/entity-framework-common-performance-mistakes-cdb8861cf0e7 ) упомянул, что это не очень хорошая практика, поскольку она создает много планов выполнения на сервере SQL.
В этом случае, как следует пересмотреть LINQ, чтобы я мог делать то же самое, но минимизировать количество сгенерированных планов выполнения?
(обратите внимание, что я не собираюсь преобразовывать его в хранимую процедуру и передавать amp; join с UDT, поскольку для этого снова требуется слишком много усилий)
Ответ №1:
В этой статье предлагаются некоторые полезные вещи, которые следует иметь в виду при написании выражений для EF. Как правило, этот пример следует иметь в виду, а не жесткое правило типа «никогда не делай этого». Это предупреждение о написании запросов, которые допускают множественный выбор, и о том, чтобы избегать этого, когда это возможно, поскольку это будет дороже.
В вашем примере с чем-то вроде «Ages» наличие жестко запрограммированного списка значений не вызывает проблем, потому что каждое выполнение использует один и тот же список. (до тех пор, пока приложение не будет повторно скомпилировано с новым списком, или у вас есть код, который по какой-либо причине изменяет список.) Примеры, в которых это может быть совершенно допустимо использовать, — это что-то вроде статусов, где у вас есть перечисление статуса. Если существует небольшое количество допустимых статусов, которые может иметь запись, то объявление общего массива допустимых статусов для использования в Contains
предложении — это нормально:
public void DeleteEnquiry(int enquiryId)
{
var allowedStatuses = new[] { Statuses.Pending, Statuses.InProgress, Statuses.UnderReview };
var enquiry = context.Enquiries
.Where(x => x.EnquiryId == enquiryId amp;amp; allowedStatuses.Contains(x.Status))
.SingleOrDefault();
try
{
if(enquiry != null)
{
enquiry.IsActive = false;
context.SaveChanges();
}
else
{
// Enquiry not found or invalid status.
}
}
catch (Exception ex) { /* handle exception */ }
}
Статусы в списке не изменятся, поэтому план выполнения является статичным для этого контекста.
Проблема в том, что вы принимаете что-то вроде параметра с критериями, которые включают список для Contains
предложения.
маловероятно, что кто-то захочет загрузить данные, в которых пользователь мог бы выбрать возраст «2, 4 и 6», но скорее они захотят выбрать что-то вроде: «>= 2», или «<=6, или «2>= 6», поэтому вместо создания метода, который принимает список допустимых возрастов:
public IEnumerable<Children> GetByAges(int[] ages)
{
return _dbContext.Children.Where(x => ages.Contains( x.Age)).ToList();
}
Вероятно, вам было бы лучше использовать ранжирование параметров:
private IEnumerable<Children> GetByAgeRange(int? minAge = null, int? maxAge = null)
{
var query = _dbContext.Children.AsQueryable();
if (minAge.HasValue)
query = query.Where(x => x.Age >= minAge.Value);
if (maxAge.HasValue)
query = query.Where(x => x.Age <= maxAge.Value);
return query.ToList();
}
private IEnumerable<Children> GetByAge(int age)
{
return _dbContext.Children.Where(x => x.Age == age).ToList();
}
Комментарии:
1. Привет, спасибо за ответ и оценку BI. Но дело в том, что возраст — это всего лишь пример. В моем сценарии массив не является статичным и меняется очень часто / драматично (размер набора данных составляет от 0 до нескольких тысяч). Я почти уверен, что arr.Contains(x=>x.value) соответствует статье «Не» .
2. Если вы ищете альтернативу, обновите свой вопрос примером, который точно демонстрирует, чего вы хотите достичь. Если вы заполняете массив на основе выбора пользователя, то вы, вероятно, в значительной степени зависли от стоимости плана выполнения. Если выбор может быть выполнен вместо этого на основе объединения с другим столбцом / критерием, то этого можно было бы избежать. Вы столкнулись с реальной проблемой производительности с вашим существующим запросом или просто беспокоитесь о возможном возникновении такой проблемы в будущем?