entity-framework - 实体框架在运行时多重包含
问题描述
我有一项服务,它传入参数来确定我想为导航属性包含多少。基于布尔参数,它连接一个实体列表以包括每个所需的外国实体。
在运行时,我想不包含导航实体或包含许多实体。我不能做的是菊花链,.Include().Include
因为我不知道基于传入的 args 包含哪些以及包含多少。
我想实现这一点,但我似乎无法传入逗号分隔的实体列表。有任何想法吗?
var res = db.Entity.Include(entityListCommaSeparated).Where(_=>_.ID == ID).FirstOrDefault();
解决方案
这看起来像一个存储库模式,如果您想尝试从调用代码中“隐藏”EF / DbContext,通常会变得混乱。
您可以考虑几个选项:
- 降低复杂度:
params Expression<Func<TEntity, object>>[] includes
在适用的存储库方法中使用 a ,然后准备在要返回多个实体时传递 OrderBy 表达式以及分页值。 - 通过简单的镜像:接受 IQueryable 作为返回类型,让消费者根据需要处理 Includes、OrderBy's、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();
}
调用者可以在调用之前了解 Linq 和.Include()
他们想要的东西.Single()
,或者做一个.Any()
.. 他们可能不需要整个实体图,因此他们可以.Select()
从实体和相关实体中提取.Include()
和执行更有效的查询来填充 ViewModel/DTO。GetById 可能会在许多地方使用,因此我们可以减少重复并在存储库中支持它。我们不需要所有的过滤场景等,调用者可以调用 GetOrders,然后在他们认为合适的时候进行过滤。
如果存储库只返回 DBSet,为什么还要打扰它呢?
- 集中低级数据过滤。例如,如果您使用软删除 (IsActive) 或正在运行多租户或显式授权。这些通用规则可以集中在存储库级别,而不必在任何触及 DbSet 的地方记住。
- 测试更简单。虽然您可以模拟 DbContext,或将其指向内存数据库,但模拟返回 IQueryable 的存储库更简单。(只需填充 a
List<TEntity>
并返回.AsQueryable()
. - 存储库处理创建和删除。创建以充当工厂,以确保为可行的实体建立所有必需的数据和关系。删除以处理数据库在幕后处理之外的软删除场景、级联/审计等。
推荐阅读
- django - Invoking Django-river manually for workflow management
- c++ - 在while循环内输入而不等待用户
- python - How can i make a Timer in Python?
- sql - 从 postgresql 中选择当前表名
- java - Java doesn't wait for asynchronous call response
- python - R reticulate 从 Github 安装 python 库
- java - 哪个传感器负责 Kotlin 中的指南针功能?
- python - 在文件中的某个单词之后附加文本
- sed - 匹配一个子字符串并在同一行替换另一个
- java - How to implement autocomplete in android with data being in cache and synced with firestore(java)