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

问题描述 投票:0回答:1

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

在运行时,我想要包含没有导航实体或许多。我不能做的是与.Include().Include的菊花链,因为我不知道基于传入args包含哪些以及包括多少。

我想实现这一点,但我似乎无法传入逗号分隔的实体列表。有任何想法吗?

var res = db.Entity.Include(entityListCommaSeparated).Where(_=>_.ID == ID).FirstOrDefault();
entity-framework
1个回答
0
投票

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

您可以考虑几个选项:

  1. 降低复杂性rabit漏洞:在适用的存储库方法中使用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()组成并执行更有效的查询来填充a ViewModel / DTO。 GetById可能会在很多地方使用,因此我们可以减少重复并在存储库中支持它。我们不需要所有过滤方案等,调用者可以调用GetOrders然后根据需要进行过滤。

如果只是返回DBSets,为什么还要使用存储库呢?

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