我当前的项目使用通用存储库接口,因此:
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的延迟加载会将这些属性保留为null,从而抛出错误。现在,我知道Include()
方法,但如果我的存储库是通用的,那么很难应用它们。我可以完全关闭它,但是当我不需要它时,EF将开始检索大量链接的东西 - 模型的结构和事物对审计日志的链接意味着EF的很多链接跟随。
有没有一种方法可以以更智能的方式进行延迟加载?是否有.Single()
和.Where()
这样的方法,我可以在DbSet
上调用,它也会带来子对象,这样我就可以特别要求包含子对象查询?
答案 0 :(得分:1)
为include路径添加一个可选参数,然后在DbSet上调用Include(str)。 Get方法示例:
public T Get<T>(Expression<Func<T, bool>> predicate, string includePath = null) where T : EntityBase
{
var query = db.Set<T>();
if( !string.IsNullorWhitespace( includePath ) )
{
query = query.Include( includePath );
}
return query.Single(predicate);
}