Entity Framework Multiple Включить во время выполнения - PullRequest
0 голосов
/ 03 сентября 2018

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

Во время выполнения я хочу включить либо нет объектов навигации, либо многие. То, что я не могу сделать, - это последовательная цепочка с .Include().Include, так как я не знаю, какие и сколько включить, основываясь на переданных в аргументах.

Я хочу добиться этого, но я не могу передать список разделенных запятыми объектов. Есть идеи?

var res = db.Entity.Include(entityListCommaSeparated).Where(_=>_.ID == ID).FirstOrDefault();

1 Ответ

0 голосов
/ 04 сентября 2018

Это похоже на шаблон репозитория и обычно становится беспорядочным, если вы хотите попытаться "спрятать" EF / DbContext от вызывающего кода.

Пара вариантов, которые вы можете рассмотреть:

  1. Вниз по дебету сложности: используйте params Expression<Func<TEntity, object>>[] includes в ваших подходящих методах репозитория, а затем будьте готовы к тому, чтобы также передавать выражения OrderBy и значения нумерации страниц, если вы хотите вернуть несколько сущностей.
  2. С помощью зеркала простоты: используйте IQueryable в качестве типа возврата и позволяйте потребителям обрабатывать значения IncB, OrderBy's, Count / Any / Skip / Take / First / ToList и .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?

  1. Централизация низкоуровневой фильтрации данных. Например, если вы используете Soft Deletes (IsActive) или работаете с несколькими арендаторами, или явная авторизация. Эти общие правила могут быть централизованы на уровне репозитория, а не запоминаться везде, где затрагивается DbSet.
  2. Тестирование проще. В то время как вы можете смоделировать DbContext или указать его на базу данных в памяти, макетировать хранилище, возвращающее IQueryable, проще. (Просто заполните List<TEntity> и верните .AsQueryable().
  3. Хранилище обрабатывает создание и удаление. Создать, чтобы служить фабрикой, чтобы гарантировать, что все необходимые данные и отношения установлены для жизнеспособного объекта. Удалить, чтобы обрабатывать сценарии мягкого удаления, каскады / аудиты и т. Д. Помимо того, что БД обрабатывает за кадром.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...