Cod*_*ner 10 c# asp.net-mvc entity-framework repository-pattern nopcommerce
我正在创建一个演示项目,其中包含使用存储库模式和依赖注入的crud操作.
这是我的结构:
方法1(非常受欢迎,许多开发人员使用)
我的存储库界面:
public partial interface IRepository<T>
{
void Insert(T entity);
}
Run Code Online (Sandbox Code Playgroud)
我的服务层:
public partial interface IEmployeeService
{
void InsertCategory(EmployeeMaster employeeMaster);
}
Run Code Online (Sandbox Code Playgroud)
我的类将实现该接口(服务):
public partial class EmployeeService : IEmployeeService
{
private readonly IRepository<EmployeeMaster> _employeeMasterRepository;
public EmployeeService(IRepository<EmployeeMaster> employeeMasterRepository)
{
this._employeeMasterRepository = employeeMasterRepository;
}
public virtual void InsertCategory(EmployeeMaster employeeMaster)
{
_employeeMasterRepository.Insert(employeeMaster);
}
Run Code Online (Sandbox Code Playgroud)
这是我的控制器:
public class HomeController : Controller
{
private readonly IEmployeeService _employeeService;
public HomeController(IEmployeeService employeeService)
{
this._employeeService = employeeService;
}
Run Code Online (Sandbox Code Playgroud)
以上是我从Nop Commerce项目(http://www.nopcommerce.com)关注的结构,我认为现在大多数开发人员现在只关注这种结构,即存储库模式和依赖注入.
以前我做的就像在我的应用程序中制作一个Bal(业务访问层)项目,然后在Bal中制作类文件并执行如下插入:
方法2:
public class MyBal()
{
public void Insert()
{
using (MyEntities context = new MyEntities ())
{
var result = context.MyTable.Add(_MyTable);
context.SaveChanges();
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
然后直接从My Mvc应用程序调用此方法,如下所示:
[HttpPost]
public ActionResult Insert(Model M)
{
MyBal bal = new MyBal ();
bal.Insert();
}
Run Code Online (Sandbox Code Playgroud)
那么为什么大多数开发人员继续创建这样一个复杂的结构,即存储库模式.任何人都可以解释方法1和方法2之间的区别?
方法1是否提高了性能,或者它与代码分离或代码的更好可维护性有关.
Cla*_*ies 11
许多人在Entity Framework之上实现了一个Repository,它本身使用了Repository Pattern.这背后的推理有一些变化; 关于这些是否有意义的决定是一个意见问题.
这是微软在他们的教程系列中展示的方式,第9部分,共10部分.由于微软证明了这种模式,因此它被广泛接受为合理的做法.
与实体框架分离.许多人努力将实体框架与其业务实体分开,并认为如果他们选择替换实体框架,他们可以在不修改其他业务逻辑的情况下更改存储库.然而,在实践中,您应该真正致力于技术,并且正确地分离实体框架逻辑是相当多的工作.最后,您最有可能最终只存在存储库中的方法,因为它是EF的处理方式,因此更改为另一个ORM仍会影响您的业务实体.
泛型.将Generics与存储库模式一起使用是一种非常常见的做法,可以最大限度地减少代码重复.我们的想法是,如果你有数百个类来执行CRUD操作,那么Generic Repository将更加统一且更易于维护,但可能灵活性稍差.
易于与依赖注入工具集成.在某些情况下,通过使用存储库模式使用依赖注入工具可能更容易.
单元测试.这与第4点一致,使用Repository Pattern为您提供了一个统一的类,可以轻松地模拟单元测试.
这绝不是一个详尽的清单,并且有很多理由不同意每一点同意它们,但这是我对围绕这种特定模式的思考过程的观察.
至于你的第二个问题,两个例子之间的区别 ......在第一种情况下,你创建了一个服务和一个存储库,它可能存在于与你的业务实体完全不同的项目或命名空间中.您的业务实体不了解或关心实体框架.如果您需要更改存储库的工作方式,它应该对您的实体几乎没有影响,实体的运行方式与它一直相同.
在第二种情况下,您直接与实体框架绑定.这个以及任何其他业务实体必须了解实体框架,对实体框架的任何更改都可能意味着更改此类或任何其他类似实体的代码.对于许多实体,这可能是一个非常漫长的过程.此外,您无法轻松测试此实体,因为您执行的任何测试都会导致写入数据库.
提供代码示例,说明为什么方法1更好地考虑测试场景.使用方法2,当您在单元测试中调用Insert方法时,您实际上将调用:
Controller.Insert> MyBal.Insert>数据库执行.
这不是我们在单元测试中想要的.在单元测试中,我们只想测试单元(代码块)而不是它的整个调用堆栈的对象图.
这是因为您已经对MyBal进行了硬编码,并且无法将其切换出来.如果我们使用方法1,我们可能会:
public class HomeController : Controller
{
private readonly IMyBalService _ibalService;
public HomeController(IMyBalService ibalService)
{
_ibalService = ibalService;
}
public ActionResult Insert(Model M)
{
ibalService.Insert();
}
}
Run Code Online (Sandbox Code Playgroud)
现在您可以让MyBal类实现IBal接口:
public class MyBal : IBalService
{
public void Insert()
{
using (MyEntities context = new MyEntities ())
{
var result = context.MyTable.Add(_MyTable);
context.SaveChanges();
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
在生产场景下,所有这些都可以像现在一样工作.但是现在你也可以制作一个BalMockService.
public class BalMockService : IBalService
{
public void Insert() {}
}
Run Code Online (Sandbox Code Playgroud)
您可以在测试时将其传递给HomeController.请注意我们如何删除所有数据库调用?测试Controller.Insert不需要它们.或者我们可以让BalMockService返回一些测试数据,但是你有一个空白所以不需要它.
该点我们从MyBal分离的HomeController和我们也标榜HomeController的需要IBalService事实某种运行.