У меня есть расширение на IQueryable, которое позволяет передавать в разделительной строке имена свойств, которые при использовании заставляют запрос не создавать JOINs и эффективно вызывает SELECT N + 1 выпуск.DbSet <T> .Include() вызывает SELECT N + 1 при использовании в методе расширения
Что я заметил, так это то, что если я называю встроенное расширение EF .Include ("property") непосредственно от DbSet, все работает нормально. Но если я использую мое расширение (я даже упростили ее просто называют .INCLUDE («свойство») ВЫБРАТЬ N + 1 происходит ...
Мои вопросы почему? Что я делаю неправильно?
Здесь вызова метода (от службы)
public MyModel[] GetAll(int page, out int total, int pageSize, string sort, string filter)
{
return _myModelRepository
.Get(page, out total, pageSize, sort, filter, "PropertyOnMyModelToInclude")
.ToArray();
}
Вот метод, который использует репозиторий добавочные
public virtual IQueryable<T> Get(int page, out int total, int pageSize, string sort, string filter = null, string includes = null)
{
IQueryable<T> query = DatabaseSet;
if (!String.IsNullOrWhiteSpace(includes))
{
//query.IncludeMany(includes); // BAD: SELECT N+1
//query.Include(includes); // BAD: SELECT N+1
}
if (!String.IsNullOrWhiteSpace(filter))
{
query.Where(filter);
}
total = query.Count(); // needed for pagination
var order = String.IsNullOrWhiteSpace(sort) ? DefaultOrderBy : sort;
var perPage = pageSize < 1 ? DefaultPageSize : pageSize;
//return query.OrderBy(order).Paginate(page, total, perPage); // BAD: SELECT N+1 (in both variations above)
//return query.IncludeMany(includes).OrderBy(order).Paginate(page, total, perPage); // BAD: SELECT N+1
return query.Include(includes).OrderBy(order).Paginate(page, total, perPage); // WORKS!
}
Вот расширение (уменьшенное только для вызова Include(), чтобы проиллюстрировать проблему)
public static IQueryable<T> IncludeMany<T>(this IQueryable<T> query, string includes, char delimiter = ',') where T : class
{
// OPTION 1
//var propertiesToInclude = String.IsNullOrWhiteSpace(includes)
// ? new string[0]
// : includes.Split(new[] {delimiter}, StringSplitOptions.RemoveEmptyEntries).Select(p => p.Trim()).ToArray();
//foreach (var includeProperty in propertiesToInclude)
//{
// query.Include(includeProperty);
//}
// OPTION 2
//if (!String.IsNullOrWhiteSpace(includes))
//{
// var propertiesToInclude = includes.Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries).AsEnumerable(); //.Select(p => p.Trim());
// propertiesToInclude.Aggregate(query, (current, include) => current.Include(include));
//}
// OPTION 3 - for testing
query.Include(includes);
return query;
}
спасибо. есть ли удобный чит-лист или какой-то другой способ легко узнать, какие методы расширения изменяют существующие и возвращают новый запрос? – zam6ak
Насколько я знаю все в LINQ и все методы расширения на IQueryable, которые мы написали, возвращают новые запросы. Некоторые старые методы ObjectQuery изменяют существующий запрос, но, надеюсь, вы не будете использовать их. –