我对 ASP.NET MVC 3 的大部分了解来自于阅读 Adam Freeman 和 Steven Senderson 所著的《Pro ASP.NET MVC 3 Framework》一书。对于我的测试应用程序,我尝试非常严格地遵循他们的示例。我使用存储库模式加上 Ninject 和 Moq,这意味着单元测试工作得很好(即不需要从数据库中提取数据)。
在书中,存储库的使用方式如下:
public class EFDbTestChildRepository
{
private EFDbContext context = new EFDbContext();
public IQueryable<TestChild> TestChildren
{
get { return context.TestChildren; }
}
public void SaveTestChild(TestChild testChild)
{
if (testChild.TestChildID == 0)
{
context.TestChildren.Add(testChild);
}
else
{
context.Entry(testChild).State = EntityState.Modified;
}
context.SaveChanges();
}
}
这是与之配套的 DbContext:
public class EFDbContext : DbContext
{
public DbSet<TestParent> TestParents { get; set; }
public DbSet<TestChild> TestChildren { get; set; }
}
请注意:为了在这个提取的示例中保持简单,我在这里省略了 Ninject 将使用的接口 ITestChildRepository。
在其他来源中,我看到了一种更通用的存储库方法,其中一个存储库足以满足整个应用程序的需要。显然,就我而言,我的应用程序中最终得到了相当多的存储库列表 - 基本上我的域模型中的每个实体都有一个存储库列表。不确定这两种方法的优缺点 - 我只是为了安全起见而遵循这本书。
最后回答我的问题:每个存储库都有自己的 DbContext -private EFDbContext context = new EFDbContext();
。我是否有可能在一个请求中面临多个 DbContext 的风险?这会导致任何显着的性能开销吗?上下文之间潜在的冲突以及对数据完整性的任何后果如何?
这是一个示例,我最终在一个控制器中拥有多个存储库。
我的两个数据库表通过外键关系链接。我的领域模型类:
public class TestParent
{
public int TestParentID { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
public virtual ICollection<TestChild> TestChildren { get; set; }
}
public class TestChild
{
public int TestChildID { get; set; }
public int TestParentID { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
public virtual TestParent TestParent { get; set; }
}
Web 应用程序包含一个允许用户创建新 TestChild 的页面。其上有一个选择框,其中包含可供选择的可用 TestParents 列表。这就是我的控制器的样子:
public class ChildController : Controller
{
private EFDbTestParentRepository testParentRepository = new EFDbTestParentRepository();
private EFDbTestChildRepository testChildRepository = new EFDbTestChildRepository();
public ActionResult List()
{
return View(testChildRepository.TestChildren);
}
public ViewResult Edit(int testChildID)
{
ChildViewModel cvm = new ChildViewModel();
cvm.TestChild = testChildRepository.TestChildren.First(tc => tc.TestChildID == testChildID);
cvm.TestParents = testParentRepository.TestParents;
return View(cvm);
}
public ViewResult Create()
{
ChildViewModel cvm = new ChildViewModel();
cvm.TestChild = new TestChild();
cvm.TestParents = testParentRepository.TestParents;
return View("Edit", cvm);
}
[HttpPost]
public ActionResult Edit(TestChild testChild)
{
try
{
if (ModelState.IsValid)
{
testChildRepository.SaveTestChild(testChild);
TempData["message"] = string.Format("Changes to test child have been saved: {0} (ID = {1})",
testChild.Name,
testChild.TestChildID);
return RedirectToAction("List");
}
}
catch (DataException)
{
//Log the error (add a variable name after DataException)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
// something wrong with the data values
return View(testChild);
}
}
仅有可用的 EFDbTestChildRepository 还不够,我还需要 EFDbTestParentRepository。它们都被分配给控制器的私有变量 - 瞧,在我看来,已经创建了两个 DbContext。或者说这是不正确的?
为了避免这个问题,我尝试使用 EFDbTestChildRepository 来访问 TestParents。但这显然只会带来那些已经连接到至少一个 TestChild 的人 - 所以不是我想要的。
这是视图模型的代码:
public class ChildViewModel
{
public TestChild TestChild { get; set; }
public IQueryable<TestParent> TestParents { get; set; }
}
如果我忘记添加一些相关代码,请告诉我。非常感谢您的建议!