C# 自动映射IEnumerable<;选择列表项>;用于下拉菜单

C# 自动映射IEnumerable<;选择列表项>;用于下拉菜单,c#,asp.net,asp.net-mvc,viewmodel,automapper,C#,Asp.net,Asp.net Mvc,Viewmodel,Automapper,问题 我目前正在添加自动映射到我的MVC项目,我被卡住了。现在我有一个用于表示数据库中数据的用户模型。我必须将该模型映射到EditUserModel,调用Edit方法时将使用该模型。EditUserModel有IEnumerable(用于下拉菜单),我似乎不知道如何映射 尝试的解决方案 到目前为止,我还没有尝试实现任何东西。我不确定IEnumerable的最佳位置或填充位置。现在它正在控制器中填充 User.cs public class User { [Key] public

问题

我目前正在添加自动映射到我的MVC项目,我被卡住了。现在我有一个用于表示数据库中数据的用户模型。我必须将该模型映射到EditUserModel,调用Edit方法时将使用该模型。EditUserModel有
IEnumerable
(用于下拉菜单),我似乎不知道如何映射

尝试的解决方案

到目前为止,我还没有尝试实现任何东西。我不确定
IEnumerable
的最佳位置或填充位置。现在它正在控制器中填充

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; }
}
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; }
}
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;
EditUserModel.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; }
}
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; }
}
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;

控制器是填充视图模型的理想场所

可以使用以下扩展方法删除卫浴代码:

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);
公共静态类EnumerableExtensions
{
公共静态IEnumerable to SelectList(此IEnumerable实例,表达式文本,表达式值,Func selectedItem=null)
{
return instance.Select(t=>newselectListItem
{
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(此LambdaExpression表达式)
{
MemberExpression body=expression.body作为MemberExpression;
if(body!=null)
{
PropertyInfo成员=body.member作为PropertyInfo;
如果(成员!=null)
{
返回成员;
}
}
抛出新ArgumentException(“表达式不是属性”);
}
}
model.Roles=context.Roles.ToSelectList(r=>r.RoleID,r=>r.Description);

为了记录在案,以下是我在对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
        });
    }
}
公共静态类EnumerableExtensions
{
公共静态IEnumerable ToSelectList(此IEnumerable实例,Func文本,Func值,Func selectedItem=null)
{
return instance.Select(t=>newselectListItem
{
Text=Convert.ToString(Text(t)),
Value=Convert.ToString(值(t)),
Selected=selectedItem!=null?selectedItem(t):false
});
}
}
不用说,这是非常简单的,并且实现了相同的功能(并且在属性路径不简单的情况下,实际上更加健壮,因为Jakub的解决方案将不适用于嵌套属性)


(这不是一个真正的答案,我把它作为一个社区wiki发布,只是为了帮助阐述一点)

好的。那么,在映射过程中是否应该忽略角色字段?为什么扩展方法使用表达式树而不仅仅是普通的lambda?@KirkWoll-I从Moq中删除了它;-)嗯,好的。但这会让你的答案比需要的更加冗长。(您可以省去整个
ToPropertyInfo
方法)@KirkWoll-这就是我正在使用的代码。我粘贴了OP需要复制/粘贴才能使用的所有内容。好的,我看到这减少了用于生成IEnumerable的代码量。但是,映射程序无法解决此问题。因此,这是在控制器中执行此操作的最佳方法。EditUserViewModel模型=Mapper.Map(用户);model.Roles=context.Roles.ToSelectList(r=>r.RoleID,r=>r.Description);