ASP.Net核心web api正确实现/调用更新方法的方法

时间:2017-03-24 09:07:18

标签: asp.net-core asp.net-core-mvc entity-framework-core

我有两个相互关联的模型如下:

 public class CoreGoal
    {
        [Key]
        public long CoreGoalId { get; set; }
        [Required]
        public string Title { get; set; }

        public virtual ICollection<Benefit> Benefits { get; set; }

        public CoreGoal()
        {

        }
    }

并且

public class Benefit
{
    [Key]
    public long BenefitId { get; set; }
    [Required]
    public string What { get; set; }

    public long CoreGoalD { get; set; }

    [ForeignKey("CoreGoalId")]
    public virtual CoreGoal CoreGoal { get; set; }
    public Benefit()
    {

    }
}

来自控制器类的我的UPDATE方法:

[Route("api/[controller]")]
    public class CoreGoalController : Controller
    {
        private readonly ICoreGoalRepository _coreGoalRepository;

        //Controller
        public CoreGoalController(ICoreGoalRepository coreGoalRepository) {
            _coreGoalRepository = coreGoalRepository;
        }

        ...

        //Update
        [HttpPut("{id}")]
        public IActionResult Update(long id, [FromBody] CoreGoal item)
        {
            if (item == null || item.CoreGoalId != id)
            {
                return BadRequest();
            }

            var coreGoal = _coreGoalRepository.Find(id);
            if (coreGoal == null)
            {
                return NotFound();
            }

            coreGoal.Title = item.Title;
            coreGoal.Benefits = item.Benefits;

            _coreGoalRepository.UpdateCoreGoal(coreGoal);
            return new NoContentResult();
        }
    }

和我的存储库:

public class CoreGoalRepository : ICoreGoalRepository
{
    private readonly WebAPIDataContext _db;

    public CoreGoalRepository(WebAPIDataContext db)
    {
        _db = db;
    }

    ...

    //Find specific
    public CoreGoal Find(long key)
    {
        return _db.CoreGoals.FirstOrDefault(t => t.CoreGoalId == key);
    }

    //Update specific
    public void UpdateCoreGoal(CoreGoal coreGoal)
    {
        _db.CoreGoals.Update(coreGoal);
        _db.SaveChanges();
    }
}

我的问题是它是一种写UPDATE方法的正确方法吗? 考虑当我做GET请求时,我回来了:

[
  {
    "coreGoalId": 1,
    "title": "Goal 1",
    "benefits": [
      {
        "benefitId": 1,
        "what": "Benefit 1",
        "coreGoalD": 0
      }
    ]
  }
] 

现在我想更新这个核心目标,所以我做了如下PUT请求:

enter image description here

它给了我

An exception of type 'Microsoft.EntityFrameworkCore.DbUpdateException' occurred in Microsoft.EntityFrameworkCore.dll but was not handled in user code 

我发送了错误的请求,或者我在控制器或存储库中错误地实现了该方法?为什么我不能仅在一个请求中部分更新父实体或子实体?

1 个答案:

答案 0 :(得分:0)

直接将您的数据模型公开为您的API是一个坏主意,尤其是通过模型绑定直接接受您的数据模型作为您的操作的参数。相反,请使用仅包含您向客户端显示的内容的ViewModel类,或者允许客户端更新的ViewModel类。在许多情况下,将此模型展平是有意义的,因此它不会包含包含其他对象的对象(就像您当前所做的那样)。

如果您的模型中的导航属性同时向两个方向发展,则可能会遇到问题。这会使序列化对象变得更加困难,并且可能使EF更难以跟踪更改。我倾向于让父对象具有其子对象的导航属性,但子对象只有外键引用(int或guid属性)回到它们的父对象。在您的情况下,这意味着从Benefit中删除虚拟CoreGoal属性。

您可能也遇到问题,因为您的Benefit类的CoreGoalID属性有拼写错误并且是CoreGoalD。

如果有任何问题可以解决您的具体问题,请告诉我。