实体框架在运行时包含多个

时间:2018-09-03 18:17:27

标签: entity-framework

我有一个传递参数的服务,该参数要包含多少导航属性。基于布尔args,它连接一个实体列表以包括每个必需的外部实体。

在运行时,我不希望包含导航实体,也可以不包含多个导航实体。 我不能做的是使用.Include().Include进行菊花链连接,因为我不知道传入的args中应该包含哪些和多少个。

我想实现这一目标,但似乎无法传递以逗号分隔的实体列表。有什么想法吗?

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

1 个答案:

答案 0 :(得分:0)

这看起来像一个存储库模式,如果要尝试从调用代码中“隐藏” EF / DbContext,通常会变得混乱。

您可以考虑以下几种选择:

  1. 降低复杂性的麻烦:在适用的存储库方法中使用params Expression<Func<TEntity, object>>[] includes,然后准备在要返回多个实体时也传递OrderBy表达式以及分页值。
  2. 通过简单性镜像:将IQueryable用作返回类型,并让消费者根据需要处理Includes,OrderBy,Counts / 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.

请记住,这不能处理自定义order by子句,对于返回实体列表的方法,也需要同样的处理。您的存储库还需要公开.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();
}

呼叫者可以在呼叫.Include()之前查看Linq和.Single()他们想要的内容,或者执行.Any()。他们可能不需要整个实体图,因此可以.Select()来自实体和没有.Include()的相关实体来组成并执行更有效的查询以填充ViewModel / DTO。 GetById可能在许多地方使用,因此我们可以减少重复并在存储库中支持它。我们不需要所有的筛选器方案等,调用者可以调用GetOrders,然后根据需要进行筛选。

如果仅返回DBSet,为什么还要打扰存储库?

  1. 集中进行低级数据过滤。例如,如果您使用软删除(IsActive)或正在运行多租户或显式授权。这些通用规则可以集中在存储库级别,而不必在触摸DbSet的任何地方都记住。
  2. 测试更简单。虽然可以模拟DbContext或将其指向内存数据库,但模拟返回IQueryable的存储库更为简单。 (只需填充List<TEntity>并返回.AsQueryable()
  3. 存储库处理创建和删除。创建以用作工厂,以确保为可行的实体建立所有必需的数据和关系。删除以处理软删除方案,级联/审计等,超出数据库在后台处理的范围。