Evg*_*eni 8 c# asp.net-mvc orm design-patterns asp.net-mvc-3
我想我已经达到了"分析瘫痪"的状态.我有一个MVC应用程序,使用EF作为ORM.所以我正在尝试决定最好的数据访问模式,到目前为止我认为将所有数据访问逻辑放入控制器是要走的路......但它听起来有点不对劲.另一种选择是创建外部存储库,处理数据交互.这是我的利弊:
如果嵌入数据访问控制器,我将得到这样的代码:
using (DbContext db = new DbContext())
{
User user = db.Users.Where(x=>x.Name == "Bob").Single();
user.Address.Street = "some st";
db.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
所以有了这个,我得到了延迟加载的全部好处,我在完成后立即关闭连接,我对where子句的灵活性 - 所有的细节.con - 我在一个方法中混合了一堆东西 - 数据检查,数据访问,UI交互.
使用Repository,我正在外部化数据访问,理论上,如果我决定使用ado.net或使用不同的数据库,则可以替换repos.但是,我没有看到实现延迟加载的良好清洁方式,以及如何控制DbContext /连接的生命周期.说,我有CRUD方法的IRepository接口,我如何加载属于给定用户的地址列表?像GetAddressListByUserId这样的方法看起来很丑陋,错误,并且会让我创建一堆同样丑陋的方法,并且在使用ORM时没什么意义.
我确信这个问题已经解决了几百万次,希望有一个解决方案..
关于存储库模式的另一个问题 - 如何处理属性对象?例如,用户有一个地址列表,您将如何检索该列表?为地址创建存储库?使用ORM,地址对象不必具有回复用户的引用,也不需要具有repo的Id字段 - 它必须拥有所有这些.更多代码,更多暴露属性..
您选择的方法很大程度上取决于您要使用的项目类型.对于需要a Rapid Application Development(RAD)方法的小型项目,在MVC项目中直接使用EF模型并在控制器中访问数据几乎可以,但项目越多,它就会变得越来越混乱你会开始遇到越来越多的问题.如果您需要良好的设计和可维护性,有几种不同的方法,但一般来说,您可以坚持以下内容:
保持控制器和视图清洁.控制器应该只控制应用程序流,不包含数据访问甚至业务逻辑.视图应该仅用于表示 - 给它一个ViewModel,它将它呈现为Html(没有业务逻辑或计算).一个ViewModel每看法是这样做的一个非常干净的方式.
典型的控制器操作如下所示:
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);
}
Run Code Online (Sandbox Code Playgroud)
由于上述原因,最好抽象您的数据访问(可测试性,易于切换数据提供者或ORM或其他等).该Repository模式是一个不错的选择,但在这里您还可以获得一些实现选项.关于通用/非通用存储库一直有很多讨论,无论是否应该返回IQueryables等等.但最终它是由您选择的.
顺便问一下,你为什么要加载延迟?通常,您确切地知道特定视图所需的数据,那么为什么要选择以延迟方式获取数据,从而进行额外的数据库调用,而不是在一次调用中急需加载所需的所有内容?就个人而言,我认为有多种Get方法来获取有或没有孩子的对象是可以的.例如
public class CompanyRepository
{
Get(int Id);
Get(string name);
GetWithEmployees(int id);
...
}
Run Code Online (Sandbox Code Playgroud)
它可能看起来有点矫枉过正,你可能会选择不同的方法,但只要你有一个你遵循的模式,维护代码就容易多了.
我个人这样做:
我有一个抽象的Domain层,它不仅包含CRUD方法,还包含专门的方法,例如UsersManager.Authenticate()等.它内部使用数据访问逻辑或数据访问层抽象(取决于我需要的抽象级别)具有).
至少有一个抽象依赖总是更好.以下是它的一些优点:
从控制器本身开始,让它有2个构造函数:一个具有抽象域访问类(例如域的外观),另一个(空)构造函数选择默认实现.这样,您的控制器在Web应用程序运行时(调用空构造函数)和单元测试期间(注入模拟域层)就可以正常运行.
此外,为了能够在以后轻松切换到另一个域,请务必注入域创建者,而不是域本身.通过这种方式,将域图层构造本地化到域创建者,您可以随时切换到另一个实现,只需重新构建域创建者(创建者,我的意思是某种工厂).
我希望这有帮助.
增加: