【问题标题】:Entity Framework error: The field X is required实体框架错误:字段 X 是必需的
【发布时间】:2016-09-02 17:45:33
【问题描述】:

我有以下课程:

public class Foo
{
        [Key] 
        public int ID { get; set; }

        [Required]
        [StringLength(100)]
        public string Name { get; set; }

        [Required]
        public float Quantity { get; set; } 
}

我正在使用以下代码更新属性Quantity

  Foo f = new Foo {ID = 2, Quantity = 10}; // Updated object  

  DbSet dbSet = this.Set(f.GetType());
  dbSet.Attach(f);
  var be = Entry(f);
  be.Property("Quantity").IsModified = true;

  DBContext.SaveChanges();

但是,代码会产生如下异常:

“‘姓名’字段为必填项”

据我所知,最后一段代码应该只更新字段Quantity,但它也考虑了字段Name

我可以通过在更新之前获取对象来避免这个错误

Foo f = DBContext.Foos.Single<Foo>( x => x.ID == 2);
f.Quantity = 10; 
DBContext.SaveChanges();

但我认为这不是一个好的选择,因为它会花费两次数据库访问。

任何建议将不胜感激。

【问题讨论】:

    标签: entity-framework ef-code-first entity-framework-6


    【解决方案1】:

    您的代码没问题。唯一的问题是检查所有属性(以及未更改的属性)的 EF 验证过程。所以,如果你设置了 Name,EF 会在 SET 子句中生成一个没有 Name 的查询。

    我的意思是,如果你运行这段代码

    Foo f = new Foo {ID = 2, Quantity = 10, Name = "Don't care"}; // Updated object  
    
    DbSet dbSet = this.Set(f.GetType());
    dbSet.Attach(f);
    var be = Entry(f);
    be.Property("Quantity").IsModified = true;
    
    DBContext.SaveChanges();
    

    EF 将运行此查询

    update [Foos]
    set [Quantity] = @p0
    where ([ID] = @p1)
    
    @p0 = 10
    @p1 = 2
    

    【讨论】:

      【解决方案2】:

      选项 1

      正如其他人所指出的,您可以创建一个存根实体,并为其所需的属性使用虚拟值。但是,您似乎有几个类具有您想要以这种方式更新的 Quantity 属性。必须知道这些类的所有必需属性会很麻烦。

      我认为更好的选择是通过添加一行来完全关闭验证:

      DBContext.Configuration.ValidateOnSaveEnabled = false;
      

      就在DBContext.SaveChanges();之前。

      我假设您按照建议简要地使用了上下文,因此没有必要再次打开验证。

      不验证Quantity 是安全的。这是一个不可为空的float,因此您永远不能无意中为它设置空值。但请注意,当您需要其他验证 [Required],例如最大值时,您必须明确添加这些。

      选项 2

      一种更高级的替代方法是覆盖上下文的ShouldValidateEntity 方法,使其跳过只有一个名为“数量”的已修改属性的实体:

      protected override bool ShouldValidateEntity(DbEntityEntry entityEntry)
      {
          if (entityEntry.State == System.Data.Entity.EntityState.Modified)
          {
              var ose = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager
                           .GetObjectStateEntry(entityEntry.Entity);
              var modifiedProperties = ose.GetModifiedProperties();
              var isValidated = modifiedProperties.Count() == 1 
                             && modifiedProperties.Any(p => p == "Quantity");
              return !isValidated;
          }
          return base.ShouldValidateEntity(entityEntry);
      }
      

      如果您愿意,您也可以使此行为可切换,例如通过向您的上下文添加一些布尔属性。

      【讨论】:

      • 我遇到了同样的问题。这有效,但我不知道为什么它在验证时失败。我有很多实体,只有当我尝试更改其中一个的简单布尔属性时才会失败,这与任何导航属性无关,我也尝试过加载它们以查看是否有问题消失但没有。我很想看看幕后发生了什么。
      【解决方案3】:

      您的类包含 Required 属性,但您没有在代码中填充此字段:

      Foo f = new Foo {ID = 2, Quantity = 10};
      

      用类似的东西替换你的代码:

      Foo f = new Foo {ID = 2, Name = "Define name of Foo", Quantity = 10};
      

      请注意,Name 属性被初始化为一个值。

      【讨论】:

      • @guillaumeracicot 我同意,这是最简单的解决方案,但是,在那段代码中我不知道类的名称(我认为从数据库中获取资源是浪费),而且我只想更新字段Quantity
      【解决方案4】:

      虽然不是 EF 解决方案,但您可以使用 Drapper 非常非常轻松地做到这一点。

      您向 Drapper 提供您要执行的更新语句,它会执行它。例如:

      public Foo Update(Foo foo)
      {
          return _Execute(foo) ? foo : null;
      }
      

      简单。简单的。快速地。没有箍跳,你有完全的控制权。

      【讨论】:

      • 我想看看 set 子句。
      • 您在提供 SQL 时确定 set 子句。将与UPDATE Foo set Quantity = @Quantity WHERE Id = @Id 类似,如果 Foo 具有 Quantity 和 Id 属性,它们将自动传递到您的 SQL 语句中。
      • 如果您需要使用 dapper 生成通用更新查询字符串,您需要保留实体的两个副本并仅在更改的字段上生成查询(如果您尝试更新名称,您的代码将不起作用)。这是实体框架。
      • 这正是我的解决方案有效的原因——它不是实体框架。它是 EF 的替代品。
      • 在我的解决方案中,您只需要一个实例副本。按照我之前发布到 Drapper 的链接 (github.com/sextondjc/Drapper)。此解决方案有效。
      【解决方案5】:

      没有必要使用输入选项。 Attach 将为您完成工作,但需要添加一个虚拟的 Name 值才能通过 EF 验证

      Foo f = new Foo {ID = 2, Name='-'}; 
      DBContext.Foos.Attach(f);
      f.Quantity = 10;
      DBContext.SaveChanges();
      

      Name 字段不会更新,但在 Attach(f) 方法之后修改了这些属性

      【讨论】:

        猜你喜欢
        • 2016-10-31
        • 1970-01-01
        • 1970-01-01
        • 2020-02-16
        • 1970-01-01
        • 2014-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多