gpt4 book ai didi

c# - 有没有更好的方法来编写通用的惰性 DbContext 查询?

转载 作者:行者123 更新时间:2023-11-30 17:50:09 27 4
gpt4 key购买 nike

到目前为止我得到的是:

public DbSet GetQueryableLazy<TEntity>()
where TEntity : class, IContextEntity
{
context.Configuration.LazyLoadingEnabled = false;
return context.Set<TEntity>();
}

我可以像这样在 Controller 操作中调用它:

IQueryable<Person> people = (IQueryable<Person>)repository.GetQueriableLazy<Person>()
.Include("Addresses");

其中存储库是 Controller 中依赖注入(inject)的结果。但似乎我上面的代码违背了依赖注入(inject)的全部目的,因为我在 Controller 中依赖 DbContext 执行操作(因为 GetQueryableLazy 返回 DbSet),如果稍后我从 Entity Framework 切换到 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);
}

有什么建议吗?

最佳答案

这是一个漏洞百出的抽象故事。每个IQueryable实现有其自身的增强功能,超越了接口(interface)的“抽象”。

每个成熟的 ORM 都有将导航属性包含到查询结果中的概念(预先加载)以防止延迟加载,这将触发 N + 1 个查询。差异已经从行话开始了。 Entity Framework 谈论“Include”,NHibernate 谈论“Fetch”,其他实现谈论“Expand”。除了这个微不足道的差异,很难从消费层隐藏真正的实现差异。

让我们通过基于表达式对预加载行为进行参数化来说明这一点。

Entity Framework (EF) 有多个 Include方法,最有趣的两个是:

  1. DbQuery.Include(string path)
  2. 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))

因此,对于作为 DAL 的 EF,您可以使用方法 2。对于 NHibernate...您不能。片段 1 中的表达式具有不同的类型,因此不能通过 params 输入。争论。

那么试试第三种方法,一个流畅的API,这样我们就可以输入不同类型的表达式了?假设

3) IJoinableQueryable<T> GetQueryable<T>(Expression<Func<T, TProperty>> includeExpression)

返回 IJoinableQueryable<T, TProperty> (想不出更好的名字)。此接口(interface)应实现 IQueryable<T> 提供了一种基于TProperty 添加下一个“Include”或“Fetch”的方法。 一个为<T>做同样的事情.这意味着,为了取悦 NHibernate,在使用 EF 时,您会使事情不必要地变得复杂。即便如此,您迟早会遇到导致不同行为或根据 DAL 排除包含的特定组合的实现细节。

结论

不要试图抽象 DAL 实现的特定功能以使 DAL 可插入。可插拔 DAL 是一种幻觉(我们现在只讨论了一个方面)。但是如果你不公开 IQueryable在您的服务层中,您可以对应用程序的其余部分隐藏大部分 DAL 功能。一个结果是您使用规范而不是表达式来参数化服务方法。

更多相关信息:http://blog.ploeh.dk/2012/03/26/IQueryableTisTightCoupling/

关于c# - 有没有更好的方法来编写通用的惰性 DbContext 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20983385/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com