У меня есть служба, которая передает параметры того, сколько я хочу включить в свойства навигации. На основе логических аргументов он объединяет список сущностей, чтобы включить каждую требуемую внешнюю сущность.
Во время выполнения я хочу либо не включать элементы навигации, либо включать их множество.
Что я не могу сделать, так это шлейфовое соединение с .Include().Include, поскольку я не знаю, что и сколько включить, основываясь на переданных в аргументах.
Я хочу добиться этого, но, похоже, я не могу передать список объектов, разделенных запятыми. Любые идеи?
var res = db.Entity.Include(entityListCommaSeparated).Where(_=>_.ID == ID).FirstOrDefault();
Я не мог использовать лямбда-выражения в этом случае, так как мне нужно было изменить включения во время выполнения на основе логических параметров включения. то есть 15 булевых значений со значением по умолчанию false, которые могут включать любую комбинацию соответствующих свойств навигации. С лямбда-выражениями 2 ^ 15 (32768) отдельных лямбда-выражений для поддержки всех возможных комбинаций включений. т.е. GetPolicy (int id, bool includeEntityA = false, bool includeEntityB = false, ....





Это похоже на шаблон репозитория и обычно становится беспорядочным, если вы хотите попытаться «скрыть» EF / DbContext от вызывающего кода.
Вы можете рассмотреть несколько вариантов:
params Expression<Func<TEntity, object>>[] includes в подходящих методах репозитория, а затем будьте готовы также передавать выражения OrderBy, а также значения разбивки на страницы, когда вы хотите вернуть несколько сущностей..Select() по мере необходимости.Опция 1:
public Order GetById(int id, params Expression<Func<Order, object>>[] includes)
{
var query = db.Orders.Where(x => x.ID == id);
// This part can be moved into an extension method or a base repository method.
if (includes.Any)
includes.Aggregate(query, (current, include) =>
{
current.Include(include);
}
// Don't use .FirstOrDefault() If you intend for 1 record to be returned, use .Single(). If it really is optional to find, .SingleOrDefault()
return query.Single();
}
//ToDo
public IEnumerable<Order> GetOrders(/* criteria?, includes?, order by?, (ascending/descending) pagination? */)
{ }
// or
public IEnumerable<Order> GetOrdersByCustomer(/* includes?, order by?, (ascending/descending) pagination? */)
{ }
// plus..
public IEnumerable<Order> GetOrdersByDate(/* includes?, order by?, (ascending/descending) pagination? */)
{ }
public bool CustomerHasOrders(int customerId)
{ }
public bool OrderExists(int id)
{ }
public int OrdersOnDate(DateTime date)
{ }
// etc. etc. etc.
Имейте в виду, что это не обрабатывает настраиваемый порядок по предложениям, и то же самое потребуется для методов, возвращающих списки сущностей. Ваш репозиторий также должен будет предоставлять методы для .Any() (DoesExist), потому что каждый любит проверяет #null при каждом возврате. :) Тоже .Count().
Вариант 2:
public IQueryable<Order> GetById(int id)
{
return db.Orders.Where(x => x.ID == id);
}
public IQueryable<Order> GetOrders()
{
return db.Orders.AsQueryable();
}
Вызывающие могут найти в Linq и .Include() то, что им нужно, прежде чем вызывать .Single(), или выполнить .Any(). Им может не понадобиться весь граф сущностей, поэтому они могут .Select() из сущности и связанных сущностей без .Include(), чтобы составить и выполнить более эффективный запрос для заполнения ViewModel / DTO. GetById может использоваться во многих местах, чтобы мы могли уменьшить дублирование и поддерживать его в репозитории. Нам не нужны все сценарии фильтрации и т. д., Вызывающие абоненты могут вызывать GetOrders, а затем фильтровать по своему усмотрению.
Зачем возиться с репозиторием, если он просто возвращает DBSets?
List<TEntity> и верните .AsQueryable().Я пробовал приведенный ниже ответ, который похож на ваш ответ, но мне что-то не хватает. // Эта жестко запрограммированная строка работает policy = db.Policys.Include ("EntityA"). Include ("EntityB"). Where (_ => .ID == ID) .FirstOrDefault (); // Этот код не работает IQueryable <Policy> policy = db.Policys.Where ( => _.ID == ID); foreach (строковый объект в include.Split (',') {policy.Include (entity);} policy = policy.FirstOrDefault (); Вышеупомянутое работает с родительским объектом верхнего уровня, но не с внешними объектами. Они возвращают null .
foreach (string entity in include.Split(',') { policies = policies.Include(entity); } Вам не хватало назначения обратно в политики.
Как упоминает ниже Стив Пи, я бы предложил использовать лямбда-выражения, а не магические строки для include. Если вам когда-либо придется проводить рефакторинг, вы получите ошибки времени компиляции, а не более неясные ошибки базы данных времени выполнения (или, что еще хуже, никаких ошибок и включений не будет).