【问题标题】:how to use automapper in Edit method .net core mvc如何在编辑方法.net core mvc中使用automapper
【发布时间】:2020-01-22 16:50:03
【问题描述】:

在我当前带有实体框架的 .net core mvc 项目中,我使用带有 DI 的 automapper。在我的编辑方法中,我需要使用视图模型更新域模型。这是我使用自动映射器的地方。但是视图模型只包含域模型的几个属性。应该保留其他属性,但是,当我应用 _context.Update(modelToSubmit); 时,它们被设置为 null 或默认值如何仅更新域模型中我实际想要更改的字段(视图模型中的那些)?

它目前在这个项目中所做的方式是在视图模型中添加所有属性,并在视图中使用@Html.HiddenFor标签,我认为这是一种不好的做法,我想摆脱它。

我有一行代码用于映射:

DomainModel model = _mapper.Map<DomainModel>(viewModel);

编辑: 我现在有(根据下面的答案):

DatabaseModel originalRecord = _unitOfWork.DatabaseModel.Get(id);
var mappedModel = _mapper.Map<ViewModel>(originalRecord);

var newDto = _mapper.Map<ViewModel, DataBaseModel>(returnedViewModel, originalRecord);

originalRecord = _mapper.Map<ViewModel, DatabaseModel>(mappedModel);
_unitOfWork.DatabaseModel.Update(originalRecord);

我的映射配置文件:

CreateMap<ViewModel, DatabaseModel>()
            .IgnoreAllPropertiesWithAnInaccessibleSetter()
            .ForPath(dest => dest.ID, opt => opt.Ignore())
            .ForPath(dest => dest.Deadline, opt => opt.Ignore())
            .ForPath(dest => dest.RecordCreated, opt => opt.Ignore())
        .ForPath(dest => dest.Status, opt => opt.Ignore())
        .ReverseMap();

当我在网站上保存模型时,我得到这个错误:

Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException:数据库 操作预计会影响 1 行,但实际上影响了 0 行。

检索originalRecord 的查询有一个AsNoTracking() 方法,但它仍然会抛出此错误。

【问题讨论】:

  • 我通常会从数据库中获取现有模型,使用视图模型中的相关字段手动更新它,然后保存。虽然我知道这种方法并没有真正使用 automapper..
  • 是的,我一直在这样做,但它有点烦人和乏味,特别是如果模型有很多字段。
  • 如果您经常使用相同的视图模型,那么您可以将手动映射提取到一个可重用的辅助函数中,这样会稍微不那么乏味。

标签: c# asp.net-mvc asp.net-core automapper


【解决方案1】:

首先,您需要创建一个仅具有用户可以更改的属性的 ViewModel。然后你应该配置你的映射器来忽略源上不存在的属性。

configuration.CreateMap<MyViewModel, MyModel>()
                        .IgnoreAllPropertiesWithAnInaccessibleSetter()
                        .ForPath(s => s.Unmapped, opt => opt.Ignore())
                        .ForPath(s => s.Id, opt => opt.Ignore())
                        .ReverseMap();

在上面的示例中,我在 Id 属性上使用了 .Ignore(),因为如果您更改主键的值,EnityFramework 将不会接受您的 SaveChanges()。即使它被更改为相同的值。

此外,当您使用_mapper.Map&lt;DomainModel&gt;(viewModel);时,您正在创建一个非常新的目标对象,并且源对象中不存在的所有属性都将为 null 或默认值。

你应该使用

model = _mapper.Map<MyViewModel, MyModel>(viewModel, model);

您可以在这个 .net 小提琴中看到一个示例:https://dotnetfiddle.net/oyFupE

此链接可以为您提供有关 AutoMapper 上忽略属性的更多信息:https://dotnettutorials.net/lesson/ignore-using-automapper-in-csharp/

编辑: 在您在问题中添加的新代码中,您的代码比您需要的多。因为您已经有一个 ViewModel 并从数据库中获取模型。现在您只需要调用一次 automapper。

public void Update(ViewModel returnedViewModel)
{
    // Gets the orininal Model from DataBase.
    DatabaseModel originalRecord = _unitOfWork.DatabaseModel.Get(id);

    // Merge original model with the ViewModel   
    originalRecord = _mapper.Map<ViewModel, DatabaseModel>(mappedModel, originalRecord);

    // SaveChanges
    _unitOfWork.DatabaseModel.Update(originalRecord);
}

您遇到的错误可能是因为在其中一个映射器中,您的实体正在丢失 Id 的值。您可以在调试时检查它。

【讨论】:

  • 在小提琴示例中: var newDto = MyMapper.GetMapper().Map(viewModel, databaseModel);给我一个错误,即 args 不匹配模型。切换没有帮助。我在 OP 中发布了新的更新代码
  • 我发布有关答案的新信息以帮助您解决更新的问题。
猜你喜欢
  • 1970-01-01
  • 2019-08-28
  • 1970-01-01
  • 2016-05-10
  • 1970-01-01
  • 1970-01-01
  • 2019-08-05
  • 2020-03-29
  • 2020-06-21
相关资源
最近更新 更多