Entity Framework 5. Несколько включений. Это возможно?
Я пытаюсь создать метод множественного включения в моем репозитории для использования следующим образом:
repository.Include<Post>(x => x.Images, x => x.Tags).First(x => x.Id == 1)
Я пробовал что-то вроде:
public IQueryable<T> Include<T>(params Expression<Func<T, Object>>[] paths) where T : class {
return paths.Aggregate(_context.Set<T>(), (x, path) => x.Include(path));
} // Include
Но я получаю ошибку:
Невозможно неявно преобразовать тип 'System.Linq.IQueryable' в 'System.Data.Entity.DbSet'.
Обратите внимание, что исходный текст включает следующее:
public static IQueryable Include ( этот источник IQueryable, Выражение > путь
), где T: class;
Могу ли я сделать эту работу, не превращая мой метод репозитория в статический?
Спасибо,
Мигель
Ответы
Ответ 1
Если вы действительно хотите создать свой собственный метод .Include
non-extension, который позволяет использовать несколько путей в одном вызове, внутренне переведя на уже предоставленный метод .Include
, вы можете сделать что-то вроде
public IQueryable<T> Include<T>(params Expression<Func<T, object>>[] paths)
where T : class
{
IQueryable<T> query = _context.Set<T>();
foreach (var path in paths)
query = query.Include(path);
return query;
}
Это довольно близко к тому, что у вас уже есть, но избегает ловушки с Enumerable.Aggregate
, с которой вы столкнулись: у вас будет такая же проблема, если вы замените IQueryable<T> query
на var query
в моей версии.
Обратите внимание, что использование многих .Include
может нанести вред производительности. Если это происходит в вашей ситуации, вы можете переписать его для использования нескольких запросов, которые вы можете запускать один за другим в транзакции.
Лично, поскольку вы можете вызывать уже предоставленный метод расширения .Include
(using System.Data.Entity;
) на любом IQueryable
, я просто напишу его как:
repository.Posts.Include(x => x.Images).Include(x => x.Tags).First(x => x.Id == 1)
Ответ 2
public ICollection<SomeClass> Filter(string name, int skip, int take,out int total, params Expression<Func<SomeClass, object>>[] includeProperties) {
IQueryable<SomeClass> query = Session.All<SomeClass>().AsNoTracking();
//query = includeProperties.Aggregate(query, (current, property) => current.Include(property));
foreach (var property in includeProperties){
query = query.Include(property);
}
if (!string.IsNullOrWhiteSpace(name)){
query = query.Where(x => x.Name.Contains(name));
var page = query.OrderBy(x => x.Name)
.Skip(skip)
.Take(take)
.GroupBy(p => new{Total = query.Count()})
.FirstOrDefault();
total = (page != null) ? page.Key.Total : 0;
if (page == null) {
return new List<SomeClass>();
}
return page.ToList();
} else {
var page = query.OrderBy(x => x.Name)
.Skip(skip)
.Take(take)
.GroupBy(p => new { Total = query.Count() })
.FirstOrDefault();
total = (page != null) ? page.Key.Total : 0;
if (page == null) {
return new List<SomeClass>();
}
return page.ToList();
}
}
Ответ 3
Я думаю, что самый короткий путь выглядит следующим образом:
public static class LinqExtensions
{
/// <summary>
/// Acts similar of .Include() LINQ method, but allows to include several object properties at once.
/// </summary>
public static IQueryable<T> IncludeMultiple<T>(this IQueryable<T> query, params Expression<Func<T, object>>[] paths)
where T : class
{
foreach (var path in paths)
query = query.Include(path);
return query;
}
}