2010-03-27 84 views
0

我確信這已被回答之前,但我花了最後三個小時尋找一個可接受的解決方案,一直無法找到任何東西,所以我道歉我的東西肯定是重複。模型綁定與父母/子女關係

我有兩個域對象,播放器和位置。球員有一個位置。我的域對象是使用NHibernate綁定到我的數據庫的POCO。我有一個需要播放器的添加動作,所以我正在使用內置的模型綁定。在我看來,我有一個下拉列表,讓用戶選擇球員的位置。下拉列表的值是該位置的標識。除了我的Position對象未通過驗證(ModelState.IsValid)之外,所有東西都可以正確填充,因爲在模型綁定時它只有一個Id,並且沒有其他所需的屬性。

ASP.NET MVC 2解決此問題的首選解決方案是什麼?

解決方案我已經試過......

  1. 取從ModelState.IsValid之前基於ID數據庫中的位置被稱爲在我的控制器的添加操作。我無法讓模型再次運行驗證,所以ModelState.IsValid總是返回false。
  2. 創建一個自定義的ModelBinder,該對象繼承自默認聯編程序並在調用基聯聯編程後從數據庫中獲取Position。 ModelBinder似乎在進行驗證,所以如果我使用默認綁定器中的任何東西,我都會被解決。這意味着我必須完全推出我自己的綁定器,並從表單中獲取每個值......對於這種常見用例,這看起來確實是錯誤和低效的。

解決方案,我認爲可能的工作,我只是想不出該怎麼辦......

    播放器使用時
  1. 關閉驗證的位置級別。
  2. 編寫一個自定義ModelBinder利用大多數屬性綁定的默認綁定,但讓我從數據庫中獲取位置,之後默認綁定運行驗證。

那麼,你們其他人怎麼解決這個問題呢?

感謝,

附:在我看來,在這種情況下在Player上有PositionId並不是一個好的解決方案。必須以更優雅的方式解決。

回答

3

不僅對於這個特定的問題,但一般來說,我會創建一個單獨的ViewModel,而不是讓視圖具有領域模型。因此,對於您的情況,您不需要將視圖的域模型過度曝光(並獲取不需要的東西),然而,關閉驗證很可能是最糟糕的解決方案

+0

所以,基本上我必須爲我所有的觀點製作DTO。對我來說似乎相當低效。其他人是否有解決方案? – DFX 2010-03-28 02:32:33

+0

我起初聽到這個想法的時候有同樣的想法。但測試和關注點分離的積極方面似乎總是勝利。對於我來說,創建另一個模型通常比調試特定於域或創建自定義模型綁定器更快。 – 2011-08-06 17:02:29

0

創建一個自定義ModelBinder,可以爲您驗證這種特殊情況。

+0

Xeb,我無法在自定義ModelBinders上找到好的信息,認爲您可以直接指向我? – DFX 2010-03-30 06:15:07

0

我在我的一個應用程序中遇到了同樣的問題。我通過創建一個繼承自DefaultModelBinder的自定義IModelBinder並使用我綁定的特定類型進行註冊來解決此問題。

訣竅是使用它只創建對實體的類型化引用而不查詢數據庫。(Read more about session.Load here in Ayende's blog

/// <summary> 
    /// Base for binding references. Usually displayed in dropdowns 
    /// </summary> 
    public class ReferenceBinder<T> : DefaultModelBinder 
     where T : class 
    { 

     private readonly ISession session; 

     public ReferenceBinder(ISession session) 
     { 
      this.session = session; 
     } 


     public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
     { 

      var idName = CreateSubPropertyName(bindingContext.ModelName, "ID"); 

      ValueProviderResult result = bindingContext.ValueProvider.GetValue(idName); 

      int value; 
      return (int.TryParse(result.AttemptedValue, out value)) ? this.session.Load<T>(value) : null; 

     } 


    } 

在你的榜樣,你會做在Global.asax中是這樣的:

ModelBinders.Binders.Add(typeof(Position), new ReferenceBinder<Position>(<pass your current session implementation or use DI/IoC>)); 

(我使用溫莎城堡創建實際的粘合劑和我在執行填充會話)

假設你的域模型是:

 public class Player { 
      public virtual Position Position {get;set;} 
     } 

     public class Position { 
      public virtual int ID {get;private set;} 
     } 

和你回發看起來像這樣:

"Position.ID" = <id from dropdown> 

編輯:你應該可能使用專用視圖模型的DTO方法。我後來知道了這一點。 Have a look here for a quick start