【问题标题】:How to update only provided properties of a pre-existing model in ASP.NET MVC?如何仅更新 ASP.NET MVC 中预先存在的模型的提供属性?
【发布时间】:2019-07-02 18:10:23
【问题描述】:

当绑定到模型时,是否可以从数据库中提供一个模型(已经填充了它的值),然后仅使用 Web 请求提供的内容更新该模型?

例如,如果我有这个模型:

public class Dog {
    public string Name {get; set;}
    public string Owner {get; set;}
}

并且可以从数据库中填充该模型,以便:

Dog.Name == "Rolo"
Dog.Owner == "Matt"

我收到一个带有以下参数的网络请求:

?name=Max

然后我想要做的是提供已经填充的模型并且只更新“名称”属性。

生成的对象将是:

Dog.Name == "Max"
Dog.Owner == "Matt"

已经从数据库中填充了 Owner 属性,我不必复制任何值、任何其他映射等。

如何使用 ASP.NET MVC 实现这一场景?

【问题讨论】:

    标签: asp.net forms model-view-controller model modelstate


    【解决方案1】:

    当更新狗的名字时,您需要将包括 DogId 在内的整个狗模型传回控制器。这样您就可以在数据库中查询狗记录并进行相应更新。以下示例使用实体框架

    public class Dog
    {
       public int DogId { get; set; }
       public string Name { get; set; }
       public string Owner { get; set; }
    } 
    
    
    [HttpPost]
    public async Task<ActionResult> UpdateDog(Dog model)
    {
          if(!ModelState.IsValid)
              return View(model);
    
          var dbDog = await db.Dogs.SingleAsync(x => x.DogId = model.DogId);
    
          // ! at the beginning is shorthand for if the condition is false
          // this is just a shorter way of doing the other example below 
          if(!string.IsNullOrEmpty(model.Name))
          {
              dbDog.Name = model.Name;
          }
    
          if(string.IsNullOrEmpty(model.Owner))
          {
              // model.Owner is null or an empty string so we don't want to 
              // update. We can leave this blank
          }
          else
          {
             // model.Owner has a value in it so we will update
             dbDog.Owner = model.Owner
          }
    
          // you can update more properties here if you wish, or ignore them
          // dbDog.Owner = model.Owner
    
          await _db.SaveChangesAsync();
    
          return View(model);
    }
    

    如果您不想将整个模型传回,您可以像现在一样传递您的 model.Name,但您还希望包含 model.DogId 以便您知道要更新数据库中的哪条记录.

    UpdateDog?name=Max&dogId=4

    希望这会有所帮助。

    // 基于注释的AutoMapper实现 您需要创建一个映射配置文件,例如:

    using AutoMapper;
    
    public class DogProfile : Profile
    {
        public DogProfile()
        {
           CreateMap<DogViewModel, Dog>()
              .ForMember(destination => destination.Owner, options => options.Condition(source => string.IsNullOrEmpty(source.Owner))
              .ForMember(destination => destination.Name, options => options.Condition(source => string.IsNullOrEmpty(source.Name));
        }
    }
    

    然后在你的 UpdateDog ActionResult 中你可以尝试:

    使用自动映射器;

    public class DogsController : Controller
    {
        private readonly IMapper _mapper;
    
        public DogsController(IMapper _mapper)
        {
            _mapper = mapper
        }
    
        [HttpPost]
        public async Task<ActionResult> UpdateDog(DogViewModel viewModel)
        {
              if(!ModelState.IsValid)
                  return View(viewModel);
    
              var dbDog = await db.Dogs.SingleAsync(x => x.DogId = viewModel.DogId);
    
              dbDog = _mapper.Map<Dog>(viewModel)
    
              await _db.SaveChangesAsync();
    
              return View(model);
        }
    }
    

    另外,不确定您如何使用 AutoMapper,但如果您有,您可能需要在 Startup.cs 文件中的下面的 sn-p 中包含该行:

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
           services.AddMvc();
    
           // Add this line 
           services.AddAutoMapper(typeof(Startup).Assembly);
        }
    }
    

    【讨论】:

    • 我知道该怎么做,感谢您的评论。但是,如果我只想更新某些属性并且我只想在请求中发布这些属性时这样做呢?
    • 嗨,马特,我更新了答案。基本上,当您通过模型发送时,您可以检查模型的某些属性是否具有值。例如,如果请求的model.Name为null或空字符串,则可以使用if语句和String.IsNullOrEmpty检查忽略它。
    • 这是一个很好的答案,现在我知道你明白我最终想要完成什么...... :) 但我想要做到的方式是“自动”,而不需要编写那些空检查.例如,我可以使用 Mapper 来识别请求中存在哪些属性,然后只更新这些属性吗?这样,不存在的属性不会被设置为 null。找我?
    • 我已更新答案,使其包含映射器实现。您仍然需要在映射配置文件中显式指定条件语句,就像在 DogProfile 类中显示的那样,但它会在更新时整理 UpdateDog ActionResult 方法。
    • 我还发现这个链接显示了类中属性的通用空/空检查。这也可能有帮助:codereview.stackexchange.com/questions/147856/…
    猜你喜欢
    • 2010-10-27
    • 2019-11-01
    • 1970-01-01
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多