ASP.NET MVC 中的 AutoMapper 更新操作 [英] AutoMapper Update Actions in ASP.NET MVC

查看:30
本文介绍了ASP.NET MVC 中的 AutoMapper 更新操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这对某些人来说可能很简单,但是我有点困惑,找不到像样的例子.假设我正在使用视图模型并且我的 POST 操作在该视图模型中进行.通常我会按照以下方式做一些事情:

This is probably quite straight forward for some, however I'm a bit confused and can't find a decent example. Say I'm using view models and my POST action takes in that view model. Typically I would do something along the following lines:

    [HttpPost]
    public ActionResult Update(UserViewModel uvm)
    {
        User user = Mapper.Map<UserViewModel, User>(uvm);
        _repository.Update(user);

        return RedirectToAction("Index");
    }

虽然这不是全貌.映射可以正常工作,但是如果我只是更新我映射的内容,那么它会删除数据库中的有价值数据,因为当然在这种情况下我不会更新密码或其他详细信息.

Although this isn't the full picture. The mapping would work fine, however if I were to just update what I've mapped then it'd get rid of valuable data in the database because of course in this case I'm not updating the password or other details.

我的存储库看起来像这样:

My repository looks something like this:

    public void Update(User user)
    {
        User u = Session.QueryOver<User>().Where(x => x.UserName == user.UserName).SingleOrDefault();

        if (u == null)
            throw new Exception("User not found");

        u.Forename = user.Forename;
        u.Surname = user.Surname;
        u.EmailAddress = user.EmailAddress;
    }

[我正在使用 NHibernate,因此一旦会话关闭(请求完成后),它就会自动将对象保存回数据库.]

所以我的问题是,我应该在我的存储库中加载用户"实体,然后更新我想要的值,然后将其保存回来,还是有其他方法可以做到这一点?我问的原因是因为它看起来有点......手册",如果你明白我的意思吗?也许是对的,但我只是想看看在这方面有更多经验的人的意见.

So my question is, in my repository should I load the "User" entity, then update the values I want, and then save it back, or is there another method to do this? The reason I ask is because it seems a bit... "manual" if you see what I mean? Perhaps it is correct, but I just wanted to see opinions of those with more experience in this area.

干杯

推荐答案

我使用以下方法:

[HttpPost]
public ActionResult Update(UserViewModel uvm)
{
    User user = _userRepository.FindById(uvm.Id);

    user.Forename = uvm.Forename;
    user.Surname = uvm.Surname;
    user.EmailAddress = uvm.EmailAddress;

    _userRepository.Update(user);

    return RedirectToAction("Index");
}

<小时>

更新:

要解决关于 AutoMapper 的评论,请执行以下操作:

To address the comments about AutoMapper here's how to proceed:

让我们以以下类为例:

public class UserViewModel
{
    public string Forename { get; set; }
    public string Surname { get; set; }
    public string EmailAddress { get; set; }
}

public class User
{
    public string Forename { get; set; }
    public string Surname { get; set; }
    public string EmailAddress { get; set; }

    public string Password { get; set; }
}

我们不想在 UI 中修改用户密码.所以我们向 AutoMapper 表达我们的意图:

We don't want to modify the user password in the UI. So we express our intention to AutoMapper:

Mapper
    .CreateMap<UserViewModel, User>()
    .ForMember(dest => dest.Password, opt => opt.Ignore());

然后:

[HttpPost]
public ActionResult Update(UserViewModel uvm)
{
    // Fetch the original model we would like to update
    User user = _userRepository.FindById(uvm.Id);

    Mapper.Map(uvm, user);
    // At this stage the user model will have its 
    // Forename, Surname and EmailAddress properties 
    // updated from the view model and its Password property
    // will remain the one we got from the repository

    _userRepository.Update(user);

    return RedirectToAction("Index");
}

<小时>

更新 2:


UPDATE 2:

为了解决有关配置 AutoMapper 的评论中的问题,我通常使用配置文件:

To address the question in the comments about configuring AutoMapper I usually use Profiles:

public class UsersProfile : Profile
{
    protected override void Configure()
    {
        Mapper
            .CreateMap<UserViewModel, User>()
            .ForMember(dest => dest.Password, opt => opt.Ignore());    

        Mapper
            .CreateMap<User, UserViewModel>();
    }
}

然后有一个注册类来注册所有的映射器:

and then have a registry class which registers all the mappers:

public class MappingsRegistry
{
    public static void Configure()
    {
        Mapper.AddProfile(new UsersProfile());
        Mapper.AddProfile(new SomeOtherProfile());
        ...
    }
}

Application_Start中调用:

MappingsRegistry.Configure();

最后我的控制器有一个对映射引擎的引用:

Finally my controllers have a reference to the mapping engine:

public class UsersController : Controller
{
    private readonly IUsersRepository _repository;
    private readonly IMappingEngine _mappingEngine;
    public ContratsFCController(IUsersRepository repository, IMappingEngine mapperEngine)
    { 
        _repository = repository;
        _mapperEngine = mapperEngine;
    }

    [AutoMap(typeof(User), typeof(UserViewModel))]
    public ActionResult Update(int id)
    {
        var user = _repository.FindById(id);
        return View(user);
    }

    [HttpPost]
    public ActionResult Update(UserViewModel uvm)
    {
        if (!ModelState.IsValid)
        {
            return View(uvm);
        }
        var user = _repository.FindById(uvm.Id);
        _mapperEngine.Map(uvm, user);
        _repository.Update(user);
        return RedirectToAction("Index");
    }
}

现在剩下的就是指示您的 DI 框架将 Mapper.Engine 属性传递给构造函数,并且在您的单元测试中显然用适当的模拟替换它们.

Now all that's left is to instruct your DI framework to pass the Mapper.Engine property to the constructor and in your unit tests obviously substitute them with an appropriate mock.

这篇关于ASP.NET MVC 中的 AutoMapper 更新操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆