我当前的项目使用通用存储库接口,因此:
public interface IDataSource : IDisposable
{
void Add<T>(T newItem) where T : EntityBase;
T Get<T>(Guid id) where T : EntityBase;
T Get<T>(Expression<Func<T, bool>> predicate) where T : EntityBase;
IQueryable<T> GetAll<T>(Expression<Func<T, bool>> predicate = null) where T : EntityBase;
int Count<T>(Expression<Func<T, bool>> predicate = null) where T : EntityBase;
bool Any<T>(Expression<Func<T, bool>> predicate = null) where T : EntityBase;
void Update<T>(T updated) where T : EntityBase;
void Delete<T>(Guid id) where T : EntityBase;
void Delete<T>(T item) where T : EntityBase;
void Commit();
}
例如,该Get
方法如下所示:
public T Get<T>(Expression<Func<T, bool>> predicate) where T : EntityBase
{
return db.Set<T>().Single(predicate);
}
我的数据上下文的实例在哪里db
,它扩展了实体框架的DbContext
. 整个事情的实现IDisposable
,以便我可以在工作单元模式的范围块中使用它,在提交更改之前等待结束,或者如果在此之前出现问题,则处理整个事情。
逻辑层使用此接口来处理更复杂的查询,以使业务逻辑与数据访问完全分离。因此,对该层的查询可能如下所示:
public List<Product> ItemsBoughtByCustomer(Guid customerID)
{
using (var db = DataAccess.GetContext())
{
List<Purchase> purchaseHistory = db.GetAll<Purchase>(p => p.CustomerID == customerID);
List<int> IDs = purchaseHistory.Select(p => p.ProductID);
return db.GetAll<Product>(p => IDs.Contains(p.ID));
}
}
(是的,我意识到可以浓缩;它在应用程序中,但例如,这更清楚。)
我的问题是有时我会返回一组对象,然后我可能想要获取它引用的一些东西。例如,当我要显示一个产品时,显示可能想要这样做:
@foreach (Comment comment in Product.Comments)
{
<div class="comment">
<span>@Html.UserDisplay(comment.Author)</span>
<span>@comment.Body</span>
</div>
}
(忽略 HTML 的质量;同样,这是一个简单的示例)
问题是,当 Entity Framework 的延迟加载在从我的查询返回实体时使这些属性为空时,这会引发错误。现在,我知道该Include()
方法,但如果我的存储库是通用的,那么很难应用它们。我可以完全关闭它,但是当我不需要它们时,EF 将开始检索大量链接的事物集合——我的模型的结构和事物与审计日志的链接意味着 EF 有很多链接到跟随。
有没有一种方法可以让我以更智能的方式进行延迟加载?是否有类似的方法.Single()
,.Where()
我可以调用该方法DbSet
,它也会带来子对象,以便我可以专门要求将子对象包含在某个查询中?