【问题标题】:MVC .NET [Required] DataAnnotations on a parent model causing invalid ModelState in a child modelMVC .NET [必需] 父模型上的 DataAnnotations 导致子模型中的 ModelState 无效
【发布时间】:2012-04-19 09:51:03
【问题描述】:

我想在保存子模型 (VehicleModel) 时“关闭”父模型 (VehicleManufacturer) 的某个属性的必填字段验证,即:

public class VehicleManufacturer
{
    public virtual Guid Id { get; set; }

    [Required]
    [StringLength(50, MinimumLength = 1)]
    public virtual string Name { get; set; }
}

public class VehicleModel
{
    public virtual Guid Id { get; set; }

    [Required]
    [StringLength(50, MinimumLength = 1)]
    public virtual string Name { get; set; }

    public virtual VehicleManufacturer Manufacturer { get; set; }
}

所以,当我保存一个新模型时,我只关心它的名称和制造商 ID,它们可以从下拉列表中选择,但是,因为制造商名称在其实体中标记为 [必需],它保存新的 VehicleModel 时使我的 ModelState 无效,因为 ManufacturerName 为 null :(

我想知道最好的方法是什么以及如何做到这一点。 我可以想到一些解决方案,但似乎都不是正确的方法:

  • 在 ModelState 检查之前设置一个“默认”ManufacturerName 值,即 "-" 只是为了满足 DataAnnotation
  • 填充制造商名称 和我的 VehicleModelView 中的 ManufacturerId - 如果你的父母不好 模型有一堆必填字段,你真的不需要在 子模型
  • 关闭子模型的 [必需] 验证(不确定 怎么样?)

你怎么看?

【问题讨论】:

  • 我猜你的模型是实体框架模型?这就是为什么您不应该使用实体模型作为视图模型的原因。 ViewModels 应该是特定的每个视图。然后你可以对不同的屏幕进行不同的验证。

标签: asp.net-mvc asp.net-mvc-3 data-annotations


【解决方案1】:

最简单的方法是为您不想显示的所需属性设置隐藏字段。

【讨论】:

  • 你好,关键是这个属性只有在创建父模型(VehicleManufacturer)时才需要,而在创建子模型(VehicleModel)时不需要。我不想填充不需要满足 ModelState 的属性?...
【解决方案2】:

一种可能的解决方案是将外键列添加到 VehicleManufacturer (VehicleManufacturerId) 到 VehicleModel 并在您的视图中使用该列。

【讨论】:

  • 接受这一点,因为这几乎就是我最终得到的结果 - 一个具有 ManufacturerId 属性的新 ViewModel,而不是完整的 Manufacturer。
【解决方案3】:

IValidatableObject 接口用于自定义模型验证。

例如:

public class VehicleModel : IValidatableObject
{
    public virtual Guid Id { get; set; }

    [StringLength(50, MinimumLength = 1)]
    public virtual string Name { get; set; }

    public virtual VehicleManufacturer Manufacturer { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if(string.IsNullOrWhiteSpace(Name))
        {
           yield return new ValidationResult("Name is required")
        } 
    }
}

然后在你的控制器中调用ModelState.IsValid

【讨论】:

    【解决方案4】:

    我最终做的是使用 ParentWithExtendedValidation : Parent 对父模型进行子类化

    在 ParentWithExtendedValidation 中标记了所有各种 [必填] 字段。

    当我想专门编辑父对象时,我使用了 ParentWithExtendedValidation 类型 -- 因为它是 Parent 的子类,一旦它通过模型验证,您可以将它转换回父类并将其传递给您的 DAL,而不会出现任何问题。

    当你在关系中使用它时,例如编辑一个引用它的孩子,你可以使用常规的 Parent 类。

    希望对你有帮助

    EG 我有一个 Person 类——具有我所有的普通虚拟属性,并且只需要 ID(以使在 person->ID 上选择的验证仍然正常工作)

    还有一个类 PersonEV

    public class PersonWithExtendedValidation : Person
    {
    
        [Required]
        public override string FullName { get; set; }
        [Required]
        public override string FirstName { get; set; }
        [Required]
        public override string LastName { get; set; }        
        [Required]
        public override string DomainName { get; set; }
        [Required]
        public override string WorkPhone { get; set; }
        [Required]
        public override string CellPhone { get; set; }
        [Required]
        public override string Email { get; set; }        
    }
    

    然后在您的视图/控制器中使用例如 PersonEV 作为模型和参数。

    检查完 ModelState.IsValid 后,将其转换回 (Person) 并照常传递到任何存储库等

    【讨论】:

      【解决方案5】:

      好的。我看了这个,意识到我的方法很浪费。

      这看起来怎么样?

      我创建了一个名为 ExtendedValidationRequired 的注解。

      它有一个静态值,可以对扩展值进行条件检查。

      [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
      
      public class ExtendedValidationRequiredAttribute : RequiredAttribute
      {
      
      
      
          // Summary:
          //     Initializes a new instance of the System.ComponentModel.DataAnnotations.RequiredAttribute
          //     class.
          public ExtendedValidationRequiredAttribute()
          {
      
          }
      
      
      
          // Summary:
          //     Checks that the value of the required data field is not empty.
          //
          // Parameters:
          //   value:
          //     The data field value to validate.
          //
          // Returns:
          //     true if validation is successful; otherwise, false.
          //
          // Exceptions:
          //   System.ComponentModel.DataAnnotations.ValidationException:
          //     The data field value was null.
          protected override ValidationResult IsValid(object value, ValidationContext validationContext)
          {
              if (ExtendedValidation.IsExtendedValidationEnabled(validationContext.ObjectType))
              {
      
                  return base.IsValid(value,validationContext);
              }
              else
              {
                  return ValidationResult.Success;                
              }
      
      
          }
      
      
      
      
      }
      

      然后我用 [ExtendedValidationRequired(typeof(MyClassName))] 标记我的有时需要(例如,当我直接编辑该类时)字段

      这也适用于其他类型的验证器。

      我实际上继续创建了一组“有时开启”验证器,并将我的设置移到了一个单独的类中: 公共静态类 ExtendedValidation { 私有静态 Dictionary extendedValidationExemptions = new Dictionary();

          /// <summary>
          /// Disable extended validation for a specific type
          /// </summary>
          /// <param name="type"></param>
          public static void DisableExtendedValidation(Type type)
          {
              extendedValidationExemptions[type] = true;
          }
          /// <summary>
          /// Clear any EV exemptions
          /// </summary>
          public static void Reset()
          {
              extendedValidationExemptions.Clear();
          }
      
          /// <summary>
          /// Check if a class should perform extended validation
          /// </summary>
          /// <param name="type"></param>
          /// <returns></returns>
          public static bool IsExtendedValidationEnabled(Type type)
          {
              if (extendedValidationExemptions.ContainsKey(type))
              {
                  return false;
              }
              else
              {
                  return true;
              }
          }
      }
      

      }

      现在我只是在编辑子项时关闭 ExtendedValidation。

      例如:编辑 Child 时,可以 DisableExtendedValidation(typeof(Parent)) 并且不会妨碍。

      编辑:嗯,我意识到这不太有效。 -- 我可以确定我在validationProperty 中查看的类吗?我想我总是可以传递父属性,但那是一个 PITA

      【讨论】:

        猜你喜欢
        • 2018-03-15
        • 1970-01-01
        • 2015-08-05
        • 1970-01-01
        • 2012-03-25
        • 1970-01-01
        • 2013-11-20
        • 2019-08-23
        • 1970-01-01
        相关资源
        最近更新 更多