如何在仅使用一个 DbContext 实例的情况下处理不同的职责
我一直在寻找我的问题的答案,但找不到答案,主要是因为我真的不知道如何表达它!
我首先尝试使用 EF 代码,并尝试在使用依赖项注入的同时实现某种存储库模式(感谢 Unity)。我还试图保持 SOLID(至少是 SRP 部分),因为我有 IStaffRepository
和 IDepartmentRepository
接口,它们又实现了 IRepository
它提供了基本的CRUD
方法。
我的问题是,当我需要更新员工部门时,如何遵守 SRP?
我读到,由于可能存在内存泄漏,对所有存储库使用单个 DbContext
实例是不好的做法,因此我不能简单地调用 IDepartmentRepository
来获取新部门这将使用我的 DbContext
的单独实例。
对我来说,显而易见的解决方案是在 IStaffRepository
中包含类似...的内容
Department GetDepartment(int id);
- 但这不会破坏 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;
}
}
在数据库中有一个 int Department_ID
字段连接到 Department 表。
我的视图中有一个下拉列表,看起来像......
@Html.DropDownListFor(m => m.SelectedDepartment, Model.DepartmentList, "--Please Select--")
对这个问题的长度表示歉意!
I have been looking around for an answer to my question but couldn't find one, mostly because I don't really know how to phrase it!
I am playing around with EF code first and trying to implement some sort of repository pattern whilst using dependency injection (thanks to Unity). I am also trying to keep to SOLID (well, the SRP part at least) in that I have IStaffRepository
and IDepartmentRepository
interfaces which in turn implement IRepository<TEntity>
which provides basic CRUD
methods.
My question is, how can I keep to the SRP when I need to update a staff members' department?
I have read that it is bad practice to use a single DbContext
instance for all repositories due to possible memory leaks and so I cannot simply call the IDepartmentRepository
to get the new department as this would use a separate instance of my DbContext
.
The obvious solution to me is to include something like...
Department GetDepartment(int id);
Within IStaffRepository
- but would this not break the SRP?
The code I have in my Controller is...
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});
}
And the StaffMember
model contains...
public class StaffMember
{
public virtual Department Department { get; set; }
}
And the StaffViewModel
looks like this...
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;
}
}
In the database there is a int Department_ID
field which hooks up to the Department table.
I have a drop down in my view which looks like...
@Html.DropDownListFor(m => m.SelectedDepartment, Model.DepartmentList, "--Please Select--")
Apologies for the length of this question!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果所有模型都基于同一数据库中的实体,则没有理由不使用单个上下文实例在同一控制器中管理它们。我会采用简单的解决方案并使用单个上下文实例。
If all of your models are based on entities in the same database, there is not reason not to use a single context instance to manage them within the same controller. I would go with the simple solution and use a single context instance.
如果您使用存储库模式,那么您至少有一个实现多个存储库接口之一的类。由于您的代码与接口耦合而不是与实现耦合,因此您不必担心。但是,您应该将存储库实现视为单例,即每个方法都应该是独立的,并且类不应该存储状态(您可以存储连接字符串,因为它基本上是一个常量)。
所以一个方法看起来像这样
这样你总是处理数据上下文,因此不应该有内存泄漏
对于SRP,存储库的作用是获取/保存对象。如果能做到这一点就好了。
If you're using the Repository pattern then you have at least a class which implements one of more repository interfaces. Since your code is coupled to an interface and not to an implementation you don't have to worry. However, you should treat the repository implementation as a singleton i.e every method should be independent and the class should not store state (you can store the conenction string since is basically a constant).
So a method look like this
This way you're always disposing the data context and thus there should be no memory leaks
As for SRP, the role of an repository is to get/save objects. If it does that it's good.
单个实例的潜在问题是完成后没有释放上下文。如果您使用依赖注入,这将在完成后处理该对象的处置。我也不推荐您上面的设计 - 您正在为 ViewModel 提供数据访问行为,而它们通常不是用于此目的的。 ViewModel 具有模型的属性,并且可能有一些特定于准备该数据的功能。将服务层注入控制器,其职责是填充该视图模型或返回模型。然后,您可以使用 automapper 将该模型映射到您的 ViewModel。还有一个简洁的属性可用于执行此映射。
查看:
http://lostechies.com/jimmybogard/ 2009/06/30/我们如何做-mvc-view-models/
The problem potentially with a single instance is not releasing the context when it is done. If you use dependency injection, this will handle the disposing of this object when it is done. I do not recommend the design you have above either - you are giving your ViewModel data access behavior, which generally they aren't purposed for. A ViewModel has properties for the model and MAYBE some functionality specific to prepare that data. Inject a service layer into your controller whose responsibility it is to populate that viewmodel OR return a model. You can then just use automapper to map that model to your ViewModel. There's a neat attribute available as well to do this mapping.
Check out:
http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/