Asp.net mvc 3 如何在仅使用DbContext的一个实例时处理不同的职责

Asp.net mvc 3 如何在仅使用DbContext的一个实例时处理不同的职责,asp.net-mvc-3,entity-framework,repository-pattern,solid-principles,Asp.net Mvc 3,Entity Framework,Repository Pattern,Solid Principles,我一直在四处寻找我的问题的答案,但找不到答案,主要是因为我真的不知道如何表达它 我首先使用EF代码,并尝试在使用依赖项注入的同时实现某种存储库模式(多亏了Unity)。我还试图保持稳定(至少是SRP部分),因为我有IStaffRepository和IDepartmentRepository接口,这些接口反过来实现IRepository,提供基本的CRUD方法 我的问题是,当我需要更新员工部门时,如何遵守SRP 我已经读到,由于可能的内存泄漏,对所有存储库使用单个DbContext实例是不好的做法

我一直在四处寻找我的问题的答案,但找不到答案,主要是因为我真的不知道如何表达它

我首先使用EF代码,并尝试在使用依赖项注入的同时实现某种存储库模式(多亏了Unity)。我还试图保持稳定(至少是SRP部分),因为我有
IStaffRepository
IDepartmentRepository
接口,这些接口反过来实现
IRepository
,提供基本的
CRUD
方法

我的问题是,当我需要更新员工部门时,如何遵守SRP

我已经读到,由于可能的内存泄漏,对所有存储库使用单个
DbContext
实例是不好的做法,因此我不能简单地调用
IDepartmentRepository
来获取新部门,因为这将使用我的
DbContext
的单独实例

对我来说,最明显的解决办法就是加入一些像

Department GetDepartment(int id);
IStaffRepository
-但这不会破坏SRP吗

我控制器中的代码是

private IStaffRepository repository;
private IDepartmentRepository departmentRepository;

public StaffController(IStaffRepository repository, IDepartmentRepository departmentRepository)
{
   this.repository = repository;
   this.departmentRepository = departmentRepository;
}

public ActionResult Edit(int id)
{
   return View(new StaffViewModel(repository.GetItem(id)));
}

[HttpPost]
public ActionResult Edit(int id, StaffViewModel model)
{
   if (!ModelState.IsValid)
      return View(model);

   var item = repository.GetItem(id);

   // throws error due to different context
   item.Department = departmentRepository.GetItem(int.Parse(model.SelectedDepartment));

   UpdateModel(item, "Item");

   repository.Save();

   return RedirectToAction("Member", new {id});
}
StaffMember
模型包含

public class StaffMember
{
   public virtual Department Department { get; set; }
}
StaffViewModel
看起来像这样

public class StaffViewModel : ViewModelBase<StaffMember>
{
   public SelectList DepartmentList {get;set;}
   public string SelectedDepartment {get;set;}

   public StaffViewModel()
   {
      var departmentRepository = new DepartmentRepository();
      DepartmentList = new SelectList(departmentRepository.GetCollection(), "ID", "Title", SelectedDepartment);   
   }

   public StaffViewModel(StaffMember item) : this()
   {
      Item = item;
      SelectedDepartment = Item.Department.ID.ToString();
   }

   public StaffViewModel(List<StaffMember> collection) : this()
   {
      Collection = collection;
   }
}  

为这个问题的长度道歉

如果所有模型都基于同一数据库中的实体,那么没有理由不在同一控制器中使用单个上下文实例来管理它们。我将使用简单的解决方案,并使用单个上下文实例。

如果您的所有模型都基于同一数据库中的实体,那么没有理由不使用单个上下文实例在同一控制器中管理它们。我将使用简单的解决方案并使用单个上下文实例。

如果您使用的是存储库模式,那么您至少有一个类实现了一个或多个存储库接口。因为您的代码是耦合到接口而不是实现的,所以您不必担心。但是,您应该将存储库实现视为一个单例,即每个方法都应该是独立的,类不应该存储状态(您可以存储conenction字符串,因为它基本上是一个常量)。 所以一个方法看起来像这样

public void Save(Entity entity)
{
   using(var db=new MyDbContext())
   {
      //do stuff
   }
}
这样,您总是在处理数据上下文,因此不应该有内存泄漏
对于SRP,存储库的作用是获取/保存对象。如果这样做就很好。

如果您使用的是存储库模式,那么您至少有一个类实现了一个或多个存储库接口。因为您的代码是耦合到接口而不是实现的,所以您不必担心。但是,您应该将存储库实现视为一个单例,即每个方法都应该是独立的,类不应该存储状态(您可以存储conenction字符串,因为它基本上是一个常量)。 所以一个方法看起来像这样

public void Save(Entity entity)
{
   using(var db=new MyDbContext())
   {
      //do stuff
   }
}
这样,您总是在处理数据上下文,因此不应该有内存泄漏
对于SRP,存储库的作用是获取/保存对象。如果它做到了这一点,那就很好。

单个实例的潜在问题是在完成时没有释放上下文。如果使用依赖项注入,则在完成时将处理此对象的处理。我也不推荐您使用上面的设计-您提供的是ViewModel数据访问行为,而这些行为通常不是为您设计的。ViewModel具有模型的属性,可能还有一些特定于准备数据的功能。将服务层注入控制器,其职责是填充该viewmodel或返回模型。然后可以使用automapper将该模型映射到ViewModel。还有一个整洁的属性可以用来进行映射

退房:

单个实例可能存在的问题是在完成时没有释放上下文。如果使用依赖项注入,则在完成时将处理此对象的处理。我也不推荐您使用上面的设计-您提供的是ViewModel数据访问行为,而这些行为通常不是为您设计的。ViewModel具有模型的属性,可能还有一些特定于准备数据的功能。将服务层注入控制器,其职责是填充该viewmodel或返回模型。然后可以使用automapper将该模型映射到ViewModel。还有一个整洁的属性可以用来进行映射

退房:

“我已经了解到,由于可能的内存泄漏,对所有存储库使用单个DbContext实例是一种不好的做法”:您是否有此语句的参考资料?我认为这是大错特错的。我从这本书里读到的,我想你误解了。Ladislav的意思是,在多个web请求之间共享上下文是一种不好的做法。为每个请求创建一个上下文(=工作单元),并将这个相同的上下文注入到您使用的所有存储库中是很好的。如果你在每次回购中都创建了自己的上下文,那么你就会遇到现在的问题。只有当您的存储库表示属于同一个部门的实体集合时(针对
部门
员工
的单个回购),您才可能这样做。但是,对于每个实体和实体之间的关系都有一个repo,您必须向所有repo中注入一个上下文。哦,好吧,要理解,这是否意味着每个请求使用一个上下文进行多个数据库连接?不,单个上下文将保持数据库连接,直到上下文被释放。因此,对于一个上下文,您只有一个连接。我将单个上下文注入到多个repo中的意思是:(取而代之的是执行此操作)我读到,由于可能的内存泄漏,在所有存储库中使用单个DbContext实例是一种不好的做法:您是否有此语句的参考?我相信是特里