2015-12-06 86 views
0

我有一個編輯ViewModel,可以完成一些數據庫工作。在ViewModel中實例化DbContext VS傳遞控制器的實例

這對我採取的這些方法有什麼影響嗎?

  1. 通在控制器的的DbContext實例的視圖模型(下面實施例1)
  2. 創建視圖模型本身內的一個新的DbContext實例(下文實施例2)

如果我通過在控制器的的DbContext這意味着.Dispose()會在某個時刻被調用(假設控制器中有.Dispose()方法)。通過在ViewModel方法本身內創建DBContext實例,這絕不會發生。這很重要嗎?


例1:

public class ModelOne 
{ 
    public int ID { get; set; } 
    public string PropA { get; set; } 
    public string PropB { get; set; } 
    public string PropC { get; set; } 
    // etc... 
} 


public class EditModelOnePropAViewModel 
{ 
    public EditModelOnePropAViewModel(ApplicationDbContext db, int id) 
    { 
     ID = id; 
     PropA = db.ModelOneDbSet 
      .Where(i => i.ID == id) 
      .Select(i => i.PropA) 
      .FirstOrDefault(); 
    } 

    public void SaveChanges(ApplicationDbContext db) 
    { 
     var modelOne = db.ModelOneDbSet.FirstOrDefault(i => i.ID == ID); 
     modelOne.PropA = PropA; 
     db.SaveChanges(); 
    } 

    public string PropA { get; set; } 
    public int ID { get; set; } 
} 


public class ControllerOne : Controller 
{ 
    private ApplicationDbContext DB = new ApplicationDbContext() { }; 

    [HttpGet] 
    public ActionResult Edit(int id) 
    { 
     var viewModel = new EditModelOnePropAViewModel(DB, id); 
     return View(viewModel); 
    } 
    [HttpPost] 
    public ActionResult Edit(EditModelOnePropAViewModel postedModel) 
    { 
     if (ModelState.IsValid) 
     { 
      postedModel.SaveChanges(DB); 
      return RedirectToAction("index"); 
     } 
     return View(postedModel); 
    } 
} 

例2:

public class ModelTwo 
{ 
    public int ID { get; set; } 
    public string PropA { get; set; } 
    public string PropB { get; set; } 
    public string PropC { get; set; } 
    // etc... 
} 


public class EditModelTwoPropAViewModel 
{ 
    public EditModelTwoPropAViewModel(int id) 
    { 
     using (var db = new ApplicationDbContext()) 
     { 
      ID = id; 
      PropA = db.ModelTwoDbSet 
       .Where(i => i.ID == id) 
       .Select(i => i.PropA) 
       .FirstOrDefault(); 
     } 
    } 

    public void SaveChanges() 
    { 
     using (var db = new ApplicationDbContext()) 
     { 
      var modelTwo = db.ModelTwoDbSet.FirstOrDefault(i => i.ID == ID); 
      modelTwo.PropA = PropA; 
      db.SaveChanges(); 
     } 

    } 
    public string PropA { get; set; } 
    public int ID { get; set; } 
} 

public class ControllerTwo : Controller 
{ 
    [HttpGet] 
    public ActionResult Edit(int id) 
    { 
     var viewModel = new EditModelTwoPropAViewModel(id); 
     return View(viewModel); 
    } 
    [HttpPost] 
    public ActionResult Edit(EditModelTwoPropAViewModel postedModel) 
    { 
     if (ModelState.IsValid) 
     { 
      postedModel.SaveChanges(); 
      return RedirectToAction("index"); 
     } 
     return View(postedModel); 
    } 
} 
+1

視圖模型不應該有任何關於你DBContext的知識。它是一個'愚蠢的'類,包含您的視圖中使用的屬性(請參閱[什麼是MVC中的ViewModel?](http://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc))。你的方法意味着你不能進行單元測試。 –

+0

爲什麼你在模型中有一個'SaveChanges'方法?你從視圖中調用它嗎? –

+0

也許我錯誤地命名了它。這是一個大型數據模型,我只是編輯了幾個屬性。因此,我想要一個模型將這兩個屬性與主數據庫支持的模型隔離開來,並將它們顯示在編輯頁面上。然後發佈我綁定到模型的屬性被編輯並更新數據庫, –

回答

3

查看模型應該是簡單的POCO的。具有您視圖所需屬性的類。沒有其他的。

public class CustomerViewModel 
{ 
    public int Id {set;get;} 
    public string FirstName {set;get;} 
    public string LastName {set;get;} 
} 

而在你的控制器,

public ActionResult Edit(int id) 
{ 
    using(var db=new YourDbContext()) 
    { 
    var c= db.Customers.FirstOrDefault(s=>s.Id==id); 
    if(c!=null) 
    { 
     var vm= new CustomerViewModel { Id=id, 
             FirstName=c.FirstName, 
             LastName=c.LastName 
            }; 
     return View(vm); 
    } 
    } 
    return View("NotFound"); 
} 

更好的方法是創建數據訪問層上的抽象,使您的控制器代碼將不會有您所使用的數據訪問技術的任何想法。這將有助於您單元測試您的控制器操作。

所以基本上你將創建一個這樣

public interface ICustomerRepository 
{ 
    CustomerDto GetCustomer(ind id); 
} 
public class EFCustomerRepository : ICustomerRepository 
{ 
    public CustomerDto GetCustomer(int id) 
    { 
     using(var db=new YourDbContext()) 
     { 
     var c= db.Customers.FirstOrDefault(s=>s.Id==id); 
     if(c!=null) 
     { 
      return new CustomerDto { Id=id, FirstName = c.FirstName }; 
     } 
     } 
     return null; 
    } 
} 

的抽象假設你有一個叫CustomerDto類,這是一個數據結構來表示客戶實體,並且是兩個網頁代碼和數據訪問代碼訪問(你也可以在一個共同的項目,並在這兩個項目中添加引用到)

而在你的控制器,你將使用ICustomerRepository的實現

public CustomerController : Controller 
{ 
    ICustomerRepository repo; 
    public CustomerController(ICustomerRepository repo) 
    { 
    this.repo =repo; 
    } 
    // You will use this.repo in your action methods now. 
} 

這將幫助您在單元測試中使用ICustomerRepository的假實現。你可以使用像Moq/FakeItEasy這樣的模擬庫來做到這一點。

您可以使用像Unity,StructureMap或Ninject這樣的依賴注入框架在您的應用程序中注入接口的具體實現。

+0

感謝您的詳細示例和解釋 - 真的很感謝! –

0

ViewModel是MVVM,而不是MVC。 MVC中的模型與MVVM中的模型相同。該模式稱爲模型 -View-Viewmodel

在MVC中,控制器負責頁面流。沒有其他的。DbContext有什麼也沒有與頁面流有關。

該模型負責業務邏輯。 DbContext有很多與業務邏輯有關。如果您想在接近表示層的位置使用數據庫,那麼模型應該創建DbContext。

你的控制器的例子2比Shyju提出的更好。現在,您可以在不需要使用DbContext的情況下測試頁面流。由於DbContext與頁面流無關,因此更有意義。

一些挑剔:POCO不是具有公共屬性和邏輯的對象。它是一個不依賴於任何框架特定的類(例如實現的特定接口)。