Большая часть моих знаний об ASP.NET MVC 3 пришла из книги Адама Фримена и Стивена Сендерсона 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; }
}
Обратите внимание: для простоты в этом извлеченном примере я оставил здесь интерфейс ITestChildRepository, который Ninject мог бы тогда используйте.
В других источниках я видел более общий подход к репозиторию, когда одного репозитория достаточно для всего приложения. Очевидно, что в моем случае я получаю целый список репозиториев в моем приложении - в основном по одному для каждой сущности в моей модели предметной области. Не уверен в плюсах и минусах этих двух подходов - я просто следил за книгой на всякий случай.
Чтобы наконец перейти к моему вопросу: у каждого репозитория есть свой собственный DbContext - private EFDbContext context = new EFDbContext ();
. Рискую ли я получить несколько DbContexts в одном запросе? И приведет ли это к значительным накладным расходам на производительность? Как насчет вероятности конфликтов между контекстами и любых последствий для целостности данных?
Вот пример, когда у меня оказалось более одного репозитория в контроллере.
Две мои таблицы базы данных связаны отношениями внешнего ключа. Мои классы модели предметной области:
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; }
}
Веб-приложение содержит страницу, которая позволяет пользователю создать новый 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.Оба они присвоены приватным переменным контроллера - и вуаля, мне кажется, что были созданы два DbContexts. Или это неправильно?
Чтобы избежать проблемы, я попытался использовать EFDbTestChildRepository для доступа к TestParents. Но это, очевидно, вызовет только тех, кто уже подключен хотя бы к одному TestChild - так что не то, что я хочу.
Вот код для модели представления:
public class ChildViewModel
{
public TestChild TestChild { get; set; }
public IQueryable<TestParent> TestParents { get; set; }
}
Пожалуйста, дайте мне знать, если я забыл включить какой-то соответствующий код. Большое спасибо за ваш совет!