尝试保存实体时 ModelState.isvalid 为 false,错误表示相关实体中需要字段

Posted

技术标签:

【中文标题】尝试保存实体时 ModelState.isvalid 为 false,错误表示相关实体中需要字段【英文标题】:ModelState.isvalid is false when trying to save an entity, error says a field is required in a related entity 【发布时间】:2016-04-28 07:02:41 【问题描述】:

我有这个代码来保存一个实体

 public class TipoDeProducto
    
        [Key]
        [ScaffoldColumn(false)]
        public int TipoDeProductoId get; set; 

        [Required]
        [MaxLength(50, ErrorMessage = "El nombre debe tener como máximo 50 caractéres")]
        public string Nombre  get; set; 

        [Required]
        public bool Estado  get; set; 

        public virtual ICollection<Producto> Productos  get; set; 
    

和产品

 public class Producto
    
        [Key]
        [ScaffoldColumn(false)]
        public int ProductoId  get; set; 

        public int TipoDeProductoId  get; set; 

        [Required]
        [MaxLength(50, ErrorMessage = "El nombre debe tener como máximo 50 caractéres")]
        public string NombreProducto  get; set; 

        [Required]
        [DataType(DataType.MultilineText)]
        [MaxLength(300, ErrorMessage = "La descripción debe tener como máximo 300 caractéres")]
        public string Descripcion  get; set; 

        public bool Estado  get; set; 


        [ForeignKey("TipoDeProductoId")]
        public virtual TipoDeProducto TipoDeProducto  get; set; 
    

编辑(POST)是这样的:

  public HttpResponseMessage PutTipoDeProducto(int id, TipoDeProducto tipoDeProducto)
        
            if (!ModelState.IsValid)
            
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            

            if (id != tipoDeProducto.TipoDeProductoId)
            
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            

            try
            
                unitOfWork.TipoDeProductoRepository.Update(tipoDeProducto);
                unitOfWork.Save();
            
            catch (DbUpdateConcurrencyException ex)
            
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
            

            return Request.CreateResponse(HttpStatusCode.OK);
        

我的索引视图是这样的:

@model List<PowerData.Comisiones.Models.TipoDeProducto>
    @using PowerData.Comisiones.Models
    @
        ViewBag.Title = "Tipos de producto";
    

    <h2>Tipos de producto</h2>

    @(html.Kendo().Grid<TipoDeProducto>()
    .Name("Grid")
    .Columns(columns =>
    
        columns.Bound(p => p.Nombre).Title("Nombre");
        columns.Bound(p => p.Estado).Title("Estado");
        columns.Command(command =>  command.Edit(); );
    )
    .ToolBar(toolbar => toolbar.Create())
    .Editable(editable => editable.Mode(GridEditMode.PopUp))

    .Pageable()
    .Sortable()
    .Scrollable(scr => scr.Height(430))
    .Filterable()
    .DataSource(dataSource => dataSource
        .WebApi()
        //.Ajax()
        //.ServerOperation(false)
        .PageSize(20)
        .Events(events => events.Error("error_handler"))
        .Model(model =>
        
            model.Id(p => p.TipoDeProductoId);
            model.Field(p => p.TipoDeProductoId).Editable(false);
        )

        .Create(create => create.Url(Url.HttpRouteUrl("DefaultApi", new  controller = "TipoDeProductos" ))) // Action invoked when the user saves a new data item
                    .Read(read => read.Url(Url.HttpRouteUrl("DefaultApi", new  controller = "TipoDeProductos" ))) // Action invoked when the grid needs data
                    .Update(update => update.Url(Url.HttpRouteUrl("DefaultApi", new  controller = "TipoDeProductos", id = "0" )))  // Action invoked when the user saves an updated data item
                    .Destroy(destroy => destroy.Url(Url.HttpRouteUrl("DefaultApi", new  controller = "TipoDeProductos", id = "0" ))) // Action invoked when the user removes a data item

        //.Create(update => update.Action("Create", "TipoDeCanales"))
            //.Read(read => read.Action("Read", "TipoDeCanales"))
            //.Update(update => update.Action("Edit", "TipoDeCanales"))
            //.Destroy(update => update.Action("Delete", "TipoDeCanales"))
    )
    )
    <script type="text/javascript">
        function error_handler(e) 
            if (e.errors) 
                var message = "Errors:\n";
                $.each(e.errors, function (key, value) 
                    if ('errors' in value) 
                        $.each(value.errors, function () 
                            message += this + "\n";
                        );
                    
                );
                toastr.error(message)
                //alert(message);
            
        
    </script>

但是,在我添加项目之后,然后尝试编辑现有行,Model.Isvalid = false,当我检查验证错误时,它说 ProductName 是必需的,这甚至不是我表上的字段我正在尝试保存,它是一个相关的实体列表

【问题讨论】:

您能否在提交之前添加您的页面生成的 HTML,就像它看起来一样?由于您的 HTML 中的 ID 无效或不匹配,绑定可能存在问题。 【参考方案1】:

我这样做是为了确保验证仅适用于当前实体:

        foreach (var key in ModelState.Keys)
            if (key.Split('.').Length > 2)
                ModelState[key].Errors.Clear();

        if (!ModelState.IsValid)
            return BadRequest(ModelState);

检查. 的出现次数意味着:如果模型状态键类似于currentDTO.relatedDTO.field,则忽略(清除)该验证错误。如果只是idcurrentDTO.validateThisField 之类的,则不会被清除。

【讨论】:

【参考方案2】:

可能默认模型绑定器也在尝试绑定相关实体productos。您可以使用 Bind 属性 ([Bind(Exclude="")]) 来覆盖它,例如

  public HttpResponseMessage PutTipoDeProducto(int id, [Bind(Exclude="productos")]TipoDeProducto tipoDeProducto)
   
         //code here
   

【讨论】:

不工作,我检查了导航属性仍然​​绑定,所有属性都设置为0,null或空并且model.isvalid仍然是false 即使在设置了Bind 属性之后?这很奇怪,而且不可能。检查您是否在任何其他操作方法中使用相同的模型并且还排除相关实体。

以上是关于尝试保存实体时 ModelState.isvalid 为 false,错误表示相关实体中需要字段的主要内容,如果未能解决你的问题,请参考以下文章

使用 MagicalRecord 保存实体 - 还尝试保存不同的实体?

当我从未将实体添加到上下文时,实体框架错误地保存了它

Core Data Fetch 在插入实体时保存关系(同时)

保存子实体的重复键值

将 UIImage 作为二进制数据保存到 CoreData 实体时出错

当您知道没有保存实体时如何处理 CoreData 中的获取请求