代码之家  ›  专栏  ›  技术社区  ›  Mohamoud Mohamed

在http post控制器中使用实体属性与分配是否更好?

  •  0
  • Mohamoud Mohamed  · 技术社区  · 8 年前

    我正在使用实体框架核心,这两种方法都可以工作,但我只是对最佳实践和性能好奇,想知道该使用什么?

    [HttpPost]
            public Message Post([FromBody] Message message)
            {
                // my old code
                // var msg = new Message { Owner = message.Owner, Text = message.Text };
                //db.Messages.AddAsync(msg)
    
                var msgEntity = db.Messages.Add(message).Entity;
                db.Messages.AddAsync(message);
                db.SaveChangesAsync();
    
                return message;
    
            }
    

    当我同时使用实体时,会发生一些奇怪的事情,它更改了自动递增的Id参数{Id:1002},当我添加它之前,下一个连续的Id被假设为{Id:11}

    1 回复  |  直到 8 年前
        1
  •  2
  •   Chris Pratt    8 年前

    永远不要直接从请求中保存任何内容。 这是你的最佳实践。前面的代码之所以优越,唯一的原因是您明确选择了实际持久化的发布值,而不是盲目地保存用户决定直接发送到数据库的任何内容。

    更好的方法是实际使用视图模型来接受用户输入。例如:

    public class MessageViewModel
    {
        public int OwnerId { get; set; }
    
        [Required]
        public string Text { get; set; }
    }
    

    然后,将其作为参数接受,并将其映射到实体:

    public async Task<IActionResult> Post([FromBody]MessageViewModel model)
    {
        if (ModelState.IsValid)
        {
            var message = new Message
            {
                Owner = db.Users.Find(model.OwnerId),
                Text = model.Text
            };
            db.Messages.Add(message);
            await db.SaveChangesAsync();
    
            return Ok(message);
        }
    
        return BadRequest(ModelState);
    }
    

    我在上述代码中做了一些重要更改:

    1. 添加了一个条件来检查 ModelState.IsValid 在继续保存之前为true。正如您现在看到的,您只是盲目地尝试保存传入的任何内容,即使这样做最终会引发数据库异常,因为缺少必需的值等等。

    2. 有了这个条件,您现在需要处理出现问题的场景。更有可能的是,您希望返回某种错误对象,以帮助客户机修复问题。通常只回来 ModelState ,它将序列化其验证错误列表,但您可能还想做其他事情。

    3. 由于这现在可能需要返回两种不同的对象类型,因此操作签名已更改为返回 IActionResult . 通常最好一直使用这种返回类型。基本上,这是一种包罗万象的回报,而具体回报如下 Message 很容易就失去了它的实用性,需要你继续做下去,然后再改变它。实际上,您应该只在绝对没有任何失败机会的情况下返回特定类型,即响应将 总是 200好吧。然而,这种情况很少发生。

    4. 视图模型只接受所有者的id,而不是完整的(大概是 ApplicationUser )对象。接受 消息 保存它也直接存在于这里。恶意用户可以使用 Owner 对象属性,允许它们潜在地更改所有不应更改的内容。通常,您应该始终允许用户操作尽可能少的数据。任何你暴露的事情都应该做 故意地 ,充分理解其含义。由于我们现在只接受一个id,因此我们需要查找具有该id的用户,以设置 物主 实体上的属性。如果碰巧有一个显式外键属性,例如 OwnerId 在…上 消息 ,你可以直接设置。

    5. 改变 AddAsync 只是 Add . 根据文档,您几乎不应该使用 添加异步

    6. 补充 await 到 SaveChangesAsync 呼叫始终等待异步操作,除非操作的完成与任何事情无关。这里绝对不是这样。 保存更改同步 可以引发应用程序需要处理的异常。不等待它,基本上只是吞下这些,让代码愉快地继续,好像没有问题。虽然这听起来可能是积极的,但绝对不是。不等待还可能导致其他问题,例如上下文可能在调用完成之前被处理。

    7. 既然我们现在在等待 保存更改同步 async 必须添加到方法签名,并且必须返回 Task<IActionResult>