【发布时间】:2012-08-28 20:27:04
【问题描述】:
目前我正在使用 sqlite 构建一个 Windows 应用程序。在数据库中有一个表说User,在我的代码中有一个Repository<User> 和一个UserManager。我认为这是一个非常常见的设计。在存储库中有一个List 方法:
//Repository<User> class
public List<User> List(where, orderby, topN parameters and etc)
{
//query and return
}
这就带来了一个问题,如果我想在UserManager.cs做一些复杂的事情:
//UserManager.cs
public List<User> ListUsersWithBankAccounts()
{
var userRep = new UserRepository();
var bankRep = new BankAccountRepository();
var result = //do something complex, say "I want the users live in NY
//and have at least two bank accounts in the system
}
您可以看到,返回List<User> 带来了性能问题,因为查询执行得比预期的要早。现在我需要把它改成IQueryable<T>:
//Repository<User> class
public TableQuery<User> List(where, orderby, topN parameters and etc)
{
//query and return
}
TableQuery<T>是sqlite驱动的一部分,几乎等同于EF中的IQueryable<T>,提供查询,不会立即执行。但是现在的问题是:在UserManager.cs中,它不知道TableQuery<T>是什么,我需要在业务层项目中添加新的引用并导入像using SQLite.Query这样的命名空间。它确实带来了糟糕的代码感觉。为什么我的业务层要知道数据库的细节?为什么业务层要知道什么是 SQLite?那么正确的设计是什么?
【问题讨论】:
-
你不能“只是”在业务层和数据访问层之间添加一个新的抽象层(接口)吗?是的,这将需要一组新的对象来表示业务层中的相同数据,以及这些对象与 DA 层中的对象之间的映射——在某种意义上,代码重复——但它应该让你在层之间有一个更清晰的划分,如果我理解你的情况。
-
我同意@Kjartan,你真正想要的是 IQueryable
,可惜 SQLite 没有,值得创建另一个层来转移到正确的类型。 -
@Kjartan @ivenxu:我没说
TableQuery<T>不正确,IQueryable<T>也不正确。即使我添加了一个新的传输接口,例如IQuery<T>,它仍然基于TableQuery<T>,当我在我的业务层使用IQuery<T>时,一切都是一样的。它只是看起来与 SQLite 无关,但实际上它戴着面具。 -
这里的 base on 对我来说并不完全清楚。它们的外观和工作方式可能相同,但如果您明智地通过接口进行分离,那么您的业务层不应该明确依赖 SQLite。它应该能够调用
GetTheStuffIWant()到DA 层,而不必知道它的实现(或者我错过了什么?)。另一方面,@DennisTraub 可能正确地推荐了一些在存储库中的加载策略,或者某种缓存,如果你不需要每次都调用数据库。 -
我认为最好的解决方法是改进 sqlite-net 以便 TableQuery 实现 IQueryable 以便您可以使用它。但也可能有一个原因,他们忽略了,只实现了 IEnumerable。
标签: c# .net architecture data-access-layer business-layer