我认为我已经达到了“分析瘫痪”的状态。
我有一个MVC应用,使用EF作为ORM。
因此,我正在尝试确定最佳的数据访问模式,到目前为止,我正在考虑将所有数据访问逻辑都放入 Controller 中是可行的..但这听起来并不正确。
另一个选择是创建一个外部存储库,以处理数据交互。
这是我的优点/缺点:
如果将数据访问嵌入到 Controller 中,我将得到如下代码:
using (DbContext db = new DbContext())
{
User user = db.Users.Where(x=>x.Name == "Bob").Single();
user.Address.Street = "some st";
db.SaveChanges();
}
这样,我就获得了延迟加载的全部好处,完成后立即关闭连接,我对where子句非常灵活-所有这些都很好。
缺点-我在一种方法中混合了很多东西-数据检查,数据访问,UI交互。
使用存储库,我可以外部化数据访问,并且从理论上讲,如果我决定使用ado.net或使用其他数据库,则可以替换存储库。
但是,我看不到一种实现延迟加载以及如何控制DbContext/连接生存时间的好方法。
说,我有带CRUD方法的IRepository接口(interface),如何加载属于给定用户的地址列表?使类似GetAddressListByUserId的方法看起来丑陋,错误,
并且会让我创建一堆同样丑陋的方法,并且在使用ORM时几乎没有意义。
我敢肯定,这个问题已经解决了上百万次,并希望在某处有解决方案。
还有一个关于存储库模式的问题-您如何处理作为属性的对象?例如。用户有一个地址列表,您将如何检索该列表?创建地址存储库?使用ORM,地址对象不必通过 repo 就具有对用户的引用,也不必具有Id字段-它必须具有所有这些。更多代码,更多公开属性。
最佳答案
您选择的方法在很大程度上取决于您将要处理的项目类型。对于需要Rapid Application Development
(RAD
)方法的小型项目,直接在MVC项目中使用EF模型并在 Controller 中进行数据访问可能几乎可以,但是项目越发展,它就会变得越困惑,并且您将开始遇到越来越多的问题。如果您想要好的设计和可维护性,可以使用几种不同的方法,但是通常可以遵循以下方法:
保持 Controller 和 View 的清洁。 Controller 应仅控制应用程序流,并且不包含数据访问甚至业务逻辑。 View 仅应用于表示-给它提供一个ViewModel,它将以Html形式呈现(没有业务逻辑或计算)。每个 View 的ViewModel
是一种非常干净的方法。
典型的 Controller Action 如下所示:
public ActionResult UpdateCompany(CompanyViewModel model)
{
if (ModelState.IsValid)
{
Company company = SomeCompanyViewModelHelper.
MapCompanyViewModelToDomainObject(model);
companyService.UpdateCompany(company);
return RedirectToRoute(/* Wherever you go after company is updated */);
}
// Return the same view with highlighted errors
return View(model);
}
由于上述原因,最好抽象化您的数据访问(可测试性,数据提供者或ORM或其他东西的轻松转换等)。
Repository
模式是一个不错的选择,但是在这里您还可以获得一些实现选项。关于通用/非通用存储库,是否应该返回IQueryable
,一直存在很多讨论。但是最终由您选择。顺便说一句,为什么要延迟加载?通常,您确切知道特定 View 所需的数据,那么为什么选择以延迟的方式获取数据,从而进行额外的数据库调用,而不是急于在一次调用中加载所需的所有数据?就个人而言,我认为可以使用多种
Get
方法来获取带有或不带有子代的对象。例如。public class CompanyRepository
{
Get(int Id);
Get(string name);
GetWithEmployees(int id);
...
}
可能看起来有些矫kill过正,您可以选择其他方法,但是只要遵循遵循的模式,维护代码就会容易得多。