2009-12-29 44 views
1

說我有一個類,如:ASP.NET MVC和NHibernate協會

public class Person 
{ 
    public virtual int Id { get; set; } 
    public virtual string Name { get; set; } 
    public virtual int SpouseId { get; set; } 
    public virtual Person Spouse { get; set; } 
} 

我已經包括SpouseId,因爲這是出的現成的方式使用(TRY)的UpdateModel模型綁定(根據ScottGu's sample MVC 2.0 code here)。在我的NHibernate映射中,我設置了SpouseId來插入= false和update = false,並且我的映射工作得很好。

我有一個「創造者」的形式在ASP.NET MVC(2),然後使用SpouseId選擇配偶:

<% 
using (Html.BeginForm()) 
{ 
%> 
    <%= Html.LabelFor(m => m.Name) %> 
    <%= Html.TextBoxFor(m => m.Name) %> 
    <%= Html.ValidationMessageFor(m => m.Name) %> 

    <%= Html.LabelFor(m => m.SpouseId) %> 
    <%= Html.EditorFor(m => m.SpouseId, "PersonPicker") %> 
    <%= Html.ValidationMessageFor(m => m.SpouseId) %> 
<% 
} 
%> 

在那裏我有一個EditorTemplate爲「PersonPicker」,它只是顯示基於ViewData中人員列表的下拉列表。

當我然後做TryUpdateModel()它工作正常,我得到我的價值填充像預計,即SpouseId設置,但不配偶。這個問題當然是NHibernate使用Person.Spouse。

我絕對寧願完全跳過SpouseId,因爲它混亂了我的模型,而且它只是因爲這個問題而存在。

我當然可以在代碼中做person.Spouse = myService.Find<Person>(person.SpouseId);,但它有一個非常非常討厭的氣味。

這樣做的最好方法是什麼?最好完全刪除SpouseId屬性。

(我想補充一點,我使用VS2008和.NET 3.5)

回答

0

好吧我真的,真的落得這樣做是使用AutoMapper和視圖模型:

public class PersonViewModel 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public int SpouseId { get; set; }  
} 

並填充視圖模型:

// set once for app Mapper.CreateMap<Person, PersonViewModel>(); 
var personViewModel = Mapper.Map<Person, PersonViewModel>(person); 

要重新填充域:

// set once for app 
// Mapper.CreateMap<PersonViewModel, Person>() 
// .ForMember(x => x.Id, o => o.Ignore()) 
// .ForMember(x => x.Spouse, o => o.MapFrom(x => PersonService.Find(x.SpouseId))); 
var viewModel = new PersonViewModel(); 
if (TryUpdateModel(viewModel)) 
{ 
    var person = PersonService.Find(viewModel.Id); 
    Mapper.Map(personViewModel, person); 
} 

唯一我不喜歡的是配偶的「反向映射」,因爲需要一個PersonService (例如。通過DI/IoC) - 但除了它的工作。

對於這個簡單的示例AutoMapper可能是矯枉過正的,如果我們不使用AutoMapper作爲「存回域模型」,我們將不會在映射配置中擁有PersonService依賴項(但是在Action方法和那可能會「違反」DRY)。

0

這是我迄今它工作要做,但我不認爲這是完美的,因爲這個原因,我有我的疑惑至於它是否是最好的/正確的方式來做到這一點。

我wen't的模型綁定器的方式,並創建如下所示的模型綁定器:從邏輯

public class MyModelBinder : DefaultModelBinder 
{ 
    public MyModelBinder(IService service) 
    { 
     this.Service = service; 
    } 

    private IService Service 
    { 
     get; 
     set; 
    } 

    protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder) 
    { 
     var modelType = bindingContext.ModelType; 

     if (/* determine if modelType is a type for association */) 
     { 
      var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 
      var id = (int?)value.ConvertTo(typeof(int)); 
      var result = id.HasValue ? this.Service.Find(modelType, id.Value) : null; 

      if (result != null) 
      { 
       return result; 
      } 
     } 

     return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder); 
    } 
} 

除了以確定類型是「包含」看來我沒問題。

繁瑣的部分來自(使用StructureMap爲IOC)在Global.asax中註冊粘合劑:

ModelBinders.Binders[typeof(Person)] = ObjectFactory.GetInstance<MyModelBinder>(); 

這我會對所有類型的事。它的工作原理,比我以前的解決方案更好,但它會更好嗎?