2013-06-18 48 views
9

我有一個從POST請求獲得的模型。由於我的視圖定義了它的POCO類型,因此從提交的數據創建的對象也是POCO。作爲POCO,它沒有覆蓋各種虛擬屬性。因此,這些虛擬屬性返回null。這反過來又意味着我必須根據外鍵進行單獨的查詢來瀏覽其屬性(如果我想做任何比保存它更復雜的事情)。我有一個POCO,我可以從DbContext獲得代理嗎?

我可以,鑑於我的模型的POCO,得到代理具有所有重寫的功能?

(我曾以爲這是什麼db.Entry().Entity是對的,但它仍然返回我的POCO對象,而不是代理。我通過鼠標懸停在斷點暫停檢查對象的運行時類型。)

+0

[將POCO對象轉換爲EntityFramework中的代理對象](http://stackoverflow.com/questions/8174200/convert-poco-object-to-proxy-object-in-entityframework) – Dennis

回答

7

這段代碼的某些內容會做你所需要的。我已使用automapper將傳入的實體中的值複製到代理版本。

代碼檢查傳入的實體是否是代理並相應地處理它。

public class Repository<T> where T : class 
{ 
    private readonly Context context; 
    private bool mapCreated = false; 
    public Repository(Context context) 
    { 
     this.context = context; 
    } 

    protected virtual T InsertOrUpdate(T e, int id) 
    { 
     T instance = context.Set<T>().Create(); 
     if (e.GetType().Equals(instance.GetType())) 
      instance = e; 
     else 
     { 
      if (!mapCreated) 
      { 
       Mapper.CreateMap(e.GetType(), instance.GetType()); 
       mapCreated = true; 
      } 
      instance = Mapper.Map(e, instance); 
     } 

     if (id == default(int)) 
      context.Set<T>().Add(instance); 
     else 
      context.Entry<T>(instance).State = EntityState.Modified; 

     return instance; 
    } 
} 

UPDATE版本中發表的意見@Colin描述不需要automapper

public class Repository<T> where T : class 
{ 
    private readonly Context context; 
    public Repository(Context context) 
    { 
     this.context = context; 
    } 

    protected virtual T InsertOrUpdate(T e, int id) 
    { 
     T instance = context.Set<T>().Create(); 
     if (e.GetType().Equals(instance.GetType())) 
     { 
      instance = e; 
     } 
     else 
     { 
      DbEntityEntry<T> entry = context.Entry(instance); 
      entry.CurrentValues.SetValues(e); 
     } 

     context.Entry<T>(instance).State = 
      id == default(int) 
       ? EntityState.Added 
       : EntityState.Modified; 

     return instance; 
    } 
} 
+1

非常感謝!這正是我需要爲各種模型類型優雅地獲得具有正確值的適當代理。 –

+1

@TheodorosChatzigiannakis我已更新代碼以使用'Entry '的通用版本。 – qujck

+0

是的,我注意到了。我已經將自己的初始代碼定製爲我手中的東西(這是一個用EF進行各種樣板程序的通用處理程序庫)。你的想法確實幫助我繼續前進。感謝您的高質量答覆! –

0

如果你想通過MVC控制器要做到這一點,你可能會使用類似這作爲動作:

[HttpPost] 
    public ActionResult Update(int? id, FormCollection form) 
    { 
     // assumes repository will handle 
     // retrieving the entity and 
     // including and navigational properties 
     var entity = repository.Get(id); 
     if (entity == null) 
     { 
      throw new InvalidOperationException(string.Format("Not found: {0}", id)); 
     } 
     if (TryUpdateModel(entity)) 
     { 
      try 
      { 
       // 
       // do other stuff, add'l validation, etc 
       repository.Update(entity); 
      } 
      catch (Exception ex) 
      { 
       // 
       // exception cleansing/handling 
       // add'l model errors 
       return View(entity); 
      } 
      return View("Success", entity); 
     }    

     return View(entity); 
    } 
+0

謝謝你的回答!這是一種有效的方法,事實上,它與我以前使用的方法類似。但是,爲了解決EF的限制,我覺得重新查詢數據庫有點浪費。這就是爲什麼我正在探索檢索代理的其他可能選項。 –

1

db.Ent 。RY()實體總是會把你返回一個POCO,並不會返回處理虛擬導航性能的實現代理對象:

var o = db.Entry(myPoco).Entity; // always returns a POCO 

您通常會得到一個代理對象,而不是POCO調用Find()時或針對數據庫上下文的Where()但是,在對象首次添加到數據庫的上下文中,這些方法將(意外地?)返回POCO而不是代理對象。實際上,你要離開的背景,並打開一個新來獲取代理:

 // create a new POCO object, and connect to it to another object already in the DB 
     MyPoco myPoco = new MyPoco(); 
     myPoco.MyOtherPocoId = myPoco2.MyOtherPocoId; // make reference to existing object 

     using (var db = new MyContext()) 
     { 
      // Add myPoco to database. 
      db.MyPocos.Add(myPoco); 
      db.SaveChanges(); 

      // One would think you get a proxy object here, but you don't: just a POCO 
      var test10 = db.MyPocos.Find(myPoco.Id);      // returns a MyPoco       
      var test11 = db.MyPocos.Where(x => x.Id == myPoco.Id).First(); // returns a MyPoco 
      var test12 = db.Entry(myPoco).Entity;       // returns a MyPoco 

      // ...so, you can't access the referenced properties through virtual navigation properties: 
      MyOtherPoco otherPoco1 = myPoco.Poco2; // returns NULL 
     } 

     // leave the context and build a new one 

     using (var db = new MyContext()) 
     { 
      // Now, the same Find() and Where() methods return a proxy object 
      var test20 = db.MyPocos.Find(myPoco.Id); // returns a proxy object 
      var test21 = db.MyPocos.Where(x => x.Id == myPoco.Id).First(); // returns a proxy object 

      // ...which means the virtual properties can be accessed as expected: 
      MyOtherPoco otherPoco = myPoco.Poco2; // works as expected 

      // Note that db.Entry().Entity still returns a POCO: 
      var test22 = db.Entry(myPoco).Entity; // returns a MyPoco 
     } 

可能有一些神奇的咒語,使在其中添加對象的上下文給你回一個代理對象,但我避風港沒有遇到它。

+0

謝謝!這類似於我已經。 EF很遺憾沒有任何東西可以自動提供相關代理。但是我猜想請求一個空的代理並手動(或可能)使用像Automapper這樣的工具進行映射,就像我們在其他答案中所建議的那樣)是最接近這個功能的。 –

相關問題