2010-08-09 31 views
1

Salut j'ai une entité appelée Utilisateur avec 2 propriétés appelées UserName et Role (qui est une référence à une autre entité appelée Role). J'essaye de mettre à jour le UserName et le RoleID d'un formulaire qui est posté. Au sein de mon action postback j'ai le code suivant:TryUpdateModel ne fonctionne pas avec Prefix et IncludeProperties

var user = new User(); 

TryUpdateModel(user, "User", new string[] { "UserName, Role.RoleID" }); 

TryUpdateModel(user, new string[] { "User.UserName, User.Role.RoleID" }); 

Cependant, aucune de ces mises à jour la propriété Role.RoleID. Si j'essaie ce qui suit:

TryUpdateModel(user, "User", new string[] { "UserName, Role" }); 

TryUpdateModel(user); 

Le RoleID est mis à jour mais la propriété RoleName est également validée. C'est pourquoi j'essaie d'être plus précis sur les propriétés à mettre à jour mais je ne peux obtenir aucun des premiers exemples à travailler.

J'apprécierais que quelqu'un puisse vous aider. Merci

+0

S'il vous plaît poster vos modèles et les données affichées. – jfar

Répondre

1

Voici une solution complète pour travailler avec n'importe quelle relation.

La première place de la ligne de code suivante dans votre événement Application_Start:

ModelBinders.Binders.DefaultBinder = new CustomModelBinder(); 

Maintenant, vous devez ajouter la classe suivante, quelque part dans votre application:

public class CustomModelBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 

     if (bindingContext.ModelType.Namespace.EndsWith("Models.Entities") && !bindingContext.ModelType.IsEnum && value != null) 
     { 
      if (Utilities.IsInteger(value.AttemptedValue)) 
      { 
       var repository = ServiceLocator.Current.GetInstance(typeof(IRepository<>).MakeGenericType(bindingContext.ModelType)); 
       return repository.GetType().InvokeMember("GetByID", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, null, repository, new object[] { Convert.ToInt32(value.AttemptedValue) }); 
      } 
      else if (value.AttemptedValue == "") 
       return null; 
     } 

     return base.BindModel(controllerContext, bindingContext); 
    } 
} 

S'il vous plaît noter le code ci-dessus peuvent avoir besoin être modifié pour répondre à vos besoins. Il appelle affectivement IRepository(). GetByID (???). Il fonctionnera lors de la liaison à toutes les entités dans l'espace de noms Models.Entities et qui ont une valeur entière. Maintenant, pour la vue, il y a un autre travail que vous avez à faire pour corriger un bogue dans ASP.NET MVC 2. Par défaut, la propriété Selected sur un SelectListItem est ignorée, donc j'ai créé mon propre DropDownListFor qui permet vous transmettre la valeur sélectionnée.

public static class SelectExtensions 
{ 
    public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string selectedValue, string optionLabel) 
    { 
     return DropDownListFor(helper, expression, selectList, selectedValue, optionLabel, null); 
    } 

    public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string selectedValue, string optionLabel, object htmlAttributes) 
    { 
     return DropDownListHelper(helper, ExpressionHelper.GetExpressionText(expression), selectList, selectedValue, optionLabel, new RouteValueDictionary(htmlAttributes)); 
    } 

    /// <summary> 
    /// This is almost identical to the one in ASP.NET MVC 2 however it removes the default values stuff so that the Selected property of the SelectListItem class actually works 
    /// </summary> 
    private static MvcHtmlString DropDownListHelper(HtmlHelper helper, string name, IEnumerable<SelectListItem> selectList, string selectedValue, string optionLabel, IDictionary<string, object> htmlAttributes) 
    { 
     name = helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name); 

     // Convert each ListItem to an option tag 
     var listItemBuilder = new StringBuilder(); 

     // Make optionLabel the first item that gets rendered 
     if (optionLabel != null) 
      listItemBuilder.AppendLine(ListItemToOption(new SelectListItem() { Text = optionLabel, Value = String.Empty, Selected = false }, selectedValue)); 

     // Add the other options 
     foreach (var item in selectList) 
     { 
      listItemBuilder.AppendLine(ListItemToOption(item, selectedValue)); 
     } 

     // Now add the select tag 
     var tag = new TagBuilder("select") { InnerHtml = listItemBuilder.ToString() }; 
     tag.MergeAttributes(htmlAttributes); 
     tag.MergeAttribute("name", name, true); 
     tag.GenerateId(name); 

     // If there are any errors for a named field, we add the css attribute 
     ModelState modelState; 

     if (helper.ViewData.ModelState.TryGetValue(name, out modelState)) 
     { 
      if (modelState.Errors.Count > 0) 
       tag.AddCssClass(HtmlHelper.ValidationInputCssClassName); 
     } 

     return tag.ToMvcHtmlString(TagRenderMode.Normal); 
    } 

    internal static string ListItemToOption(SelectListItem item, string selectedValue) 
    { 
     var tag = new TagBuilder("option") { InnerHtml = HttpUtility.HtmlEncode(item.Text) }; 

     if (item.Value != null) 
      tag.Attributes["value"] = item.Value; 

     if ((!string.IsNullOrEmpty(selectedValue) && item.Value == selectedValue) || item.Selected) 
      tag.Attributes["selected"] = "selected"; 

     return tag.ToString(TagRenderMode.Normal); 
    } 
} 

maintenant à votre vue, vous pouvez dire:

<%= Html.DropDownListFor(m => m.User.Role, Model.Roles, Model.User.Role != null ? Model.User.Role.RoleID.ToString() : "", "-- Please Select --")%> 
<%= Html.ValidationMessageFor(m => m.User.Role, "*")%> 

La propriété Rôle mettra automatiquement à jour lorsque vous appelez TryUpdateModel dans votre contrôleur et vous devez faire aucun travail supplémentaire au fil de cela. Bien que ce soit beaucoup de code au début, j'ai trouvé cette approche permet d'économiser des tas de code à long terme.

Espérons que cela aide.

0

Pensez à appeler TryUpdateModel deux fois, une fois pour l'utilisateur. Une fois pour le rôle. Attribuez ensuite le rôle à l'utilisateur.

var user = new User(); 
var role = new Role(); 

TryUpdateModel(user, new string[] { "UserName" }); 
TryUpdateModel(role, new string[] { "RoleID" }); 

user.Role = role; 

Voir si cela fonctionne.

+0

Salut merci pour votre réponse, mais j'ai réussi à trouver quelque chose qui me permet d'appeler TryUpdateModel plusieurs fois. – nfplee