2009-12-29 66 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>(); 

这我会对所有类型的事。它的工作原理,比我以前的解决方案更好,但它会更好吗?