到目前为止我得到的是:
public DbSet GetQueryableLazy<TEntity>()
where TEntity : class, IContextEntity
{
context.Configuration.LazyLoadingEnabled = false;
return context.Set<TEntity>();
}
我可以在控制器动作中调用它:
IQueryable<Person> people = (IQueryable<Person>)repository.GetQueriableLazy<Person>()
.Include("Addresses");
其中存储库是控制器中依赖注入的结果。但似乎上面的代码违背了依赖注入的全部目的,因为我在控制器中依赖于DbContext进行操作(因为GetQueryableLazy返回DbSet),如果稍后我将从实体框架切换到NHibernate,我将不得不替换:
(IQueryable<Person>)repository.GetQueriableLazy<Person>()
.Include("Addresses");
到处!
我想要实现的是,如果我可以创建附加到“DbContext.include()”所有“参数”的泛型方法并根据这些附件返回查询,那么结果将如下所示:
public IQueryable<TEntity> GetQueryableLazy<TEntity>(params IContextEntity[] contextEntities)
where TEntity : class, IContextEntity
{
context.Configuration.LazyLoadingEnabled = false;
return context.Set<TEntity>().Include(contextEntities);
}
有什么建议吗?
答案 0 :(得分:1)
这是漏洞的抽象故事。每个IQueryable
实现都有自己的增强功能,超越了接口的“抽象”。
每个成熟的ORM都有一个概念,即在查询结果中包含导航属性(急切加载),以防止延迟加载,这将触发N + 1个查询。差异已经从语言开始了。实体框架讨论“包含”,NHibernate关于“获取”,其他实现关于“扩展”。除了这个微不足道的差异之外,很难隐藏真实的实现差异与消费层。
让我们通过努力根据表达式参数化预测加载行为来说明这一点。
实体框架(EF)有几种Include
方法,最有趣的两种方法是:
DbQuery.Include(string path)
QueryableExtensions.Include<T, TProperty> (Expression<Func<T, TProperty>> path)
因此,如果你想抽象出来,你有两个选择:
1)IQueryable<T> GetQueryable<T>(params string[] includes)
2)IQueryable<T> GetQueryable<T>(params Expression<Func<T, object>>[] includeExpressions)
好的,让我们继续2)。现在看NHibernate。使用NHibernate的LINQ API,您可以编写
// snippet 1
var customers = session.Query<Customer>()
.FetchMany(c => c.Orders)
.ThenFetchMany(o => o.OrderLines)
使用EF,这将是
// snippet 2
var customers = context.Set<Customer>()
.Include(c => c.Orders.Select(o => o.OrderLines))
所以使用EF作为DAL你可以使用方法2.使用NHibernate ...你不能。代码段1中的表达式具有不同的类型,因此params
参数无法输入它们。
所以尝试第三种方法,一种流畅的API,这样我们就可以输入不同类型的表达式了?我们说
3)IJoinableQueryable<T> GetQueryable<T>(Expression<Func<T, TProperty>> includeExpression)
返回IJoinableQueryable<T, TProperty>
(想不出更好的名字)。此接口应实现IQueryable<T>
并提供一种方法,根据TProperty
和添加下一个“包含”或“获取”来执行同样适用于<T>
。这意味着为了取悦NHibernate,当使用EF时,你会让事情变得不必要。即便如此,您迟早会遇到导致不同行为的实施细节,或者根据DAL排除包含的特定组合。
不要尝试抽象DAL实现的特定功能,以使DAL可插入。可插拔的DAL是一种错觉(我们现在只涉及一个方面)。但是,如果您未在服务层中公开IQueryable
,则可以从应用程序的其余部分隐藏大部分DAL功能。一个结果是您使用规范而不是表达式来参数化服务方法。
更多相关信息:http://blog.ploeh.dk/2012/03/26/IQueryableTisTightCoupling/