2012-06-07 49 views
2

問題Automapper映射的IEnumerable <SelectListItem>的下拉菜單

我目前將自動映射到我的MVC項目,我堅持。現在我有一個用戶模型用來表示數據庫中的數據。我必須將該模型映射到EditUserModel,EditUserModel將在調用Edit方法時使用。 EditUserModel有IEnumerable<SelectListItem>(下拉菜單),我似乎無法弄清楚如何映射。

嘗試性解決方案

截至目前我還沒有嘗試過實施什麼。我不確定IEnumerable<SelectListItem>的最佳位置或填充位置。現在它正在控制器中填充。

User.cs

public class User 
{ 
    [Key] 
    public int UserID { get; set; } 

    public string Username { get; set; } 

    public string Password { get; set; } 

    public int RoleID { get; set; } 

    [ForeignKey("RoleID")] 
    public virtual Role Role { get; set; } 
} 

EditUserModel.cs

public class EditUserViewModel 
{ 
    [HiddenInput(DisplayValue = false)] 
    public int UserID { get; set; } 

    [Required] 
    public String Username { get; set; } 

    [Required] 
    [DataType(DataType.Password)] 
    public string Password { get; set; } 

    [DisplayName("Role")] 
    [Required] 
    public int RoleID { get; set; } 

    //The trouble field 
    public IEnumerable<SelectListItem> Roles { get; set; } 
} 

Controller.cs

EditUserViewModel model = new EditUserViewModel(); 
//Population of the dropdown menu 
model.Roles = context.Roles 
    .ToList() 
    .Select(x => new SelectListItem 
    { 
     Text = x.Description, 
     Value = x.RoleID.ToString() 
    }); 
//Mapping that the automaper will take care of 
model.UserID = user.UserID; 
model.Username = user.Username; 
model.RoleID = user.RoleID; 

回答

5

爲了記錄在案,這裏是我的意見的Jakub的回答談到:

public static class EnumerableExtensions 
{ 
    public static IEnumerable<SelectListItem> ToSelectList<T, TTextProperty, TValueProperty>(this IEnumerable<T> instance, Func<T, TTextProperty> text, Func<T, TValueProperty> value, Func<T, bool> selectedItem = null) 
    { 
     return instance.Select(t => new SelectListItem 
     { 
      Text = Convert.ToString(text(t)), 
      Value = Convert.ToString(value(t)), 
      Selected = selectedItem != null ? selectedItem(t) : false 
     }); 
    } 
} 

不用多說,這是非常簡單並且完成相同的事情(並且事實上,在屬性路徑非簡單的情況下更加健壯,因爲Jakub的解決方案不適用於嵌套屬性)。

(這不是一個真正的答案,我把它作爲社區維基發佈,只是爲了幫助闡述一個觀點)

+0

好的我看到,減少了用於生成IEnumerable 的代碼量。但映射器無法解決它。所以這是在你的控制器中完成它的最好方法。 EditUserViewModel model = Mapper.Map (user); model.Roles = context.Roles.ToSelectList(r => r.RoleID,r => r.Description); –

1

控制器是填充您的視圖模型的理想場所。

您可以使用該擴展方法去除管道代碼:

public static class EnumerableExtensions 
{ 
    public static IEnumerable<SelectListItem> ToSelectList<T, TTextProperty, TValueProperty>(this IEnumerable<T> instance, Expression<Func<T, TTextProperty>> text, Expression<Func<T, TValueProperty>> value, Func<T, bool> selectedItem = null) 
    { 
     return instance.Select(t => new SelectListItem 
     { 
      Text = Convert.ToString(text.ToPropertyInfo().GetValue(t, null)), 
      Value = Convert.ToString(value.ToPropertyInfo().GetValue(t, null)), 
      Selected = selectedItem != null ? selectedItem(t) : false 
     }); 
    } 

    public static PropertyInfo ToPropertyInfo(this LambdaExpression expression) 
    { 
     MemberExpression body = expression.Body as MemberExpression; 

     if (body != null) 
     { 
      PropertyInfo member = body.Member as PropertyInfo; 
      if (member != null) 
      { 
       return member; 
      } 
     } 

     throw new ArgumentException("Expression is not a Property"); 
    } 
} 

model.Roles = context.Roles.ToSelectList(r => r.RoleID, r => r.Description); 
+0

好的。那麼應該在映射過程中忽略Roles字段? –

+0

爲什麼你的擴展方法使用表達式樹而不是普通的lambda? –

+0

@KirkWoll - 我把它從Moq上撕下來了;-) –