2010-09-06 7 views
0

Ci-dessous, lors du chargement initial (Edition), tout s'affiche correctement. Toutefois, lorsque je POST (action ci-dessous), il semble que cela se passe et essaie de récupérer les modèles ProductAttribute séparément, avec l'ID du produit, qui échoue rapidement. Comment empêcher mon implémentation de Binder d'essayer de relier les collections en tant qu'entités distinctes?Objet complexe ModelBinder NHibernate avec collections

Merci!

Modèle

public class Product { 
    virtual public long Id { get; set; } 

    virtual public string Name { get; set; } 

    private IList<ProductAttribute> _productAttributes; 

    public virtual IList<ProductAttribute> ProductAttributes { 
     get{ 
     if(_productAttributes == null){ 
      _productAttributes = new List<ProductAttribute>(); 
     } 
     return _productAttributes; 
     } 
     set{ 
     _productAttributes = value; 
     } 
    } 
} 

Voir

<%using (Html.BeginForm(new {id = Model.Id > 0 ? (long?)Model.Id : null})) {%> 
<table class="form"> 
    <% for(var i=0; i < Model.ProductAttributes.Count; i++){ 
    var pa = Model.ProductAttributes[i]; %> 
    <tr> 
    <th><%: Model.ProductAttributes[i].Name %></th> 
    <td> 
    <%: Html.Hidden("ProductAttributes.Index", i) %> 
    <% if(pa.CanSpecifyValueDirectly()){ %> 
    <%: Html.TextBoxFor(model => model.ProductAttributes[i].Value) %> 
    <% } else { %> 
    <%: Html.DropDownListFor(model => model.ProductAttributes[i].Value, new SelectList(pa.MarketAttribute.AttributeLevels, "id", "Name", pa.AttributeLevel)) %> 
    <% } %> 
    </td> 
    </tr> 
    <input type="submit" value="Save" /> 
</table> 
<%}%> 

Contrôleur

public ActionResult Edit(long id, Product product) { 
    ViewData.Model = product; 
    if (ModelState.IsValid) { 
     var results = product.Update(); 
     ViewData["results"] = results; 
     if (!results.Error) { 
      return RedirectToAction("Show", new { id = id }); 
     } 
    } 

    return View(); 
} 

Binder

public class StackModelBinder : DefaultModelBinder { 
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) { 
     var modelInterface = modelType.GetInterface("IModel"); 
     if (modelInterface == null) { 
      return base.CreateModel(controllerContext, bindingContext, modelType); 
     } 

     var value = bindingContext.ValueProvider.GetValue("id").RawValue.ToString(); 
     if (string.IsNullOrEmpty(value)) { 
      return base.CreateModel(controllerContext, bindingContext, modelType); 
     } 

     var id = Convert.ChangeType(value, typeof (long)); 
     var assembly = Assembly.GetAssembly(modelType); 
     var dao = assembly.GetType(string.Concat(assembly.GetName().Name, ".core.GlobalDao`1[", modelType.FullName, "]")); 

     if (dao == null) { 
      return base.CreateModel(controllerContext, bindingContext, modelType); 
     } 

     var method = dao.GetMethod("Get"); 
     return method.Invoke(null, new[] {id}); 
    } 
} 

Répondre

1

En règle générale, il est une mauvaise idée de pousser les entités à travers le modèle de liaison - ils ont tendance à être un peu trop complexe pour qu'il puisse traiter, sans parler de la choses passionnantes qui se passe dans les ORM modernes, tels comme des proxies dynamiques, qui peuvent donner le ModelBinder ou l'ORM correspond.

Votre meilleur pari ici est de changer les règles et de créer une classe dédiée pour prendre les modifications et les transférer au contrôleur. Cette classe peut être compatible avec ModelBinder et vous avez l'avantage supplémentaire de séparer l'interface utilisateur des entités de domaine.

+0

Dans l'intérêt de DRY, je suis obligé de ne pas maintenir deux objets qui représentent essentiellement la même chose. D'autres solutions? – hoffmanc

+0

Oh, je vous sens en termes de DRY. Sauf que ce n'est pas la même chose - l'un est chargé de prendre les données dans le contrôleur, l'autre est responsable de votre entité de domaine. Pensez que le code CQRS n'est pas dupliqué. –

Questions connexes