实体框架错误:字段X是必需的

时间:2016-09-02 17:45:33

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

我有以下课程:

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();

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

任何建议将不胜感激。

5 个答案:

答案 0 :(得分:2)

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

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

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

@p0 = 10
@p1 = 2

EF将运行此查询

php artisan queue:work

答案 1 :(得分:2)

选项1

正如其他人所指出的那样,您可以为其所需属性创建一个具有虚拟值的存根实体。但是,您似乎有几个具有Quantity属性的类,您希望以这种方式更新。必须知道这些类的所有必需属性是非常麻烦的。

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

DBContext.Configuration.ValidateOnSaveEnabled = false;

DBContext.SaveChanges();之前。

我假设您按照建议简要使用上下文,因此无需再次启用验证。

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

选项2

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

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);
}

如果需要,您也可以将此行为切换为可切换,例如向您的上下文添加一些布尔属性。

答案 2 :(得分:1)

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

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

用以下代码替换您的代码:

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

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

答案 3 :(得分:0)

虽然不是EF解决方案,但您可以使用Drapper非常轻松地完成此操作。

您向Drapper提供要执行的更新语句,它将执行它。 E.g:

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

简单。简单。快速。没有箍跳&amp;你有完全的控制权。

答案 4 :(得分:0)

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

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

字段Name不会更新,但在Attach(f)方法

之后修改了这些属性