您可以在存储库界面中有两种方法 - 一种用于导航引用,另一种用于导航集合:
public interface IRepository<T>
{
void LoadNavigationReference<TReference>(T entity,
Expression<Func<T, TReference>> navigationProperty,
params Expression<Func<TReference, object>>[] includes)
where TReference : class;
void LoadNavigationCollection<TElement>(T entity,
Expression<Func<T, ICollection<TElement>>> navigationProperty,
params Expression<Func<TElement, object>>[] includes)
where TElement : class;
}
它们也应该支持包括其他嵌套导航属性。实施将是:
public class Repository<T> : IRepository<T>
where T : class
{
private readonly MyContext _dbContext;
public Repository(MyContext dbContext)
{
_dbContext = dbContext;
}
public void LoadNavigationReference<TReference>(T entity,
Expression<Func<T, TReference>> navigationProperty,
params Expression<Func<TReference, object>>[] includes)
where TReference : class
{
if (includes == null || includes.Length == 0)
_dbContext.Entry(entity).Reference(navigationProperty).Load();
else
_dbContext.Entry(entity).Reference(navigationProperty).Query()
.IncludeMultiple(includes).Load();
}
public void LoadNavigationCollection<TElement>(T entity,
Expression<Func<T, ICollection<TElement>>> navigationProperty,
params Expression<Func<TElement, object>>[] includes)
where TElement : class
{
if (includes == null || includes.Length == 0)
_dbContext.Entry(entity).Collection(navigationProperty).Load();
else
_dbContext.Entry(entity).Collection(navigationProperty).Query()
.IncludeMultiple(includes).Load();
}
}
上面使用的IncludeMultiple
扩展方法取自Ladislav Mrnka's answer here。
您问题中的示例将如下所示:
repository.LoadNavigationCollection(ticket, i => i.TicketItems);
ticket.TicketItems.Clear();
哪里repository
是类型IRepository<Ticket>
。
如果TicketItem
有另一个导航属性,比如TicketItemDetails
,你可以用这种方式急切地加载它TicketItems
:
repository.LoadNavigationCollection(ticket, i => i.TicketItems,
t => t.TicketItemDetails);
编辑
顺便说一句,作为关于通用存储库的关键旁注:以上是通用存储库的一部分,它实际上有 16 种方法,我在项目的早期阶段使用过,然后我停止扩展它并完全放弃这种风格。
该存储库一开始有大约 5 种方法(就像您在 Internet 上看到的大多数常用存储库一样)。仅使用这 5 种方法而不会失去很多 Entity Framework 的功能是不可能的。因此,我需要根据项目的实际需求逐步扩展它,并且在我将其从项目中删除之前,它从未变得“完整”。
问题是:如果你向某人展示接口(“这里我有一个超级通用且独立于技术的数据访问接口”),他会立即说“啊哈,你正在使用实体框架!”。原因是几乎每个方法都只是 Entity Framework 方法的包装,您无法通过使用接口方法的其他名称来隐藏它。整个界面有 EF DbContext
/ Code-First 的味道。
现在,尝试使用实体框架以外的另一种技术来实现该接口。您很可能会遇到与我相同的问题:缺少很多方法来利用其他技术的强大功能,或者现有方法的参数错误,或者您无法合理地使用其他方法实现的方法太多技术。
我什至失败并失去了为单元测试构建该接口的内存实现的所有乐趣。
在我看来,这样的通用存储库是泄漏抽象的典型示例,您想到的真正实现通过整个接口闪耀。
但是如果你不能抽象出实体框架的使用,那么构建一个通用的存储库接口是毫无意义的。