无法在db更新上保存更改。可能是奇怪的延迟加载行为?

时间:2017-06-18 00:45:27

标签: c# asp.net asp.net-mvc entity-framework

现在,我的代码看起来很简单:

public class FooController : Controller
{
    private readonly ApplicationDbContext db;

    public FooController()
    {
        db = new ApplicationDbContext();
    }

    public ActionResult Update(int id) 
    {
        Foo foo = db.Foos.Find(id);
        foo.X = "new string";
        db.SaveChanges();
        return Redirect("Index", "Home");
    }
}

假设Foo有一个属性X,一个字符串和一个属性Bars,一个Bar实体的集合。该属性存在一个约束,即集合中必须有1到100个条形。

我目前遇到以下异常:

Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.

我调试并打印出实际错误:

Property: "Bars", Error: "Must have between 1 and 100 bars"

这使我很困惑,因为我知道foo的特定实例在其集合中有5个条。所以我在db.SaveChanges()行放了一个断点,并使用VS工具将鼠标悬停在foo实例上,并发现它确实在集合中有5个Bars。当我继续运行该程序时,更新已成功完成。起初我想,这很奇怪。也许存在低级竞争条件(我说低级别因为我没有在应用级别执行任何异步/线程)并且断点允许其他线程赶上。也就是说,直到我使用断点再次运行更新,而悬停在foo实例上,等待几秒钟,然后继续运行程序。错误返回。

所以我认为当我将鼠标悬停在foo上并且加载是保存更改所必需的时候,我会懒得加载一些东西。这是一个已知的问题?我是否应该发布代码的其他部分以找出正在发生的事情?

编辑:对于临时解决方法,如果这会增加更多证据。以下添加允许该方法按预期工作:

public ActionResult Update(int id) 
{
    Foo foo = db.Foos.Find(id);
    foo.X = "new string";
    Debug.WriteLine(foo.Bars);
    db.SaveChanges();
}

显然这是一个绑带,我想知道这里到底发生了什么。

另一个编辑:添加如何在Foo.Bars上实现验证

public class Foo 
{
    public string X {get;set;}

    [MinMaxLength]
    public virtual ICollection<Bar> Bars {get; set;}
}

MinMaxLength看起来如下:

public class MinMaxLength : ValidationAttribute
{
    public int Min { get; set; } = 1;
    public int Max { get; set; } = 100;

    public MinMaxLength()
        : base("Must have between 1 and 100")
    {

    }

    public MinMaxLength(string errorMessage)
        : base(errorMessage)
    {

    }

    public override bool IsValid(object value)
    {
        if (value == null)
        {
            return true;
        }
        var coll = value as ICollection;
        if (coll == null)
        {
            return false;
        }

        var count = coll.Count;
        return count >= Min && count <= Max;
    }
}

2 个答案:

答案 0 :(得分:0)

Foo foo = db.Foos.Find(id);
if (foo != null)
{
    foo.X = "new string";
    db.Foos.Attach(foo);
    var entry = db.Entry(foo);
    entry.Property(x => x.X).IsModified = true;
    db.SaveChanges();
}

这应生成以下SQL:

UPDATE    dbo.Foos
SET       X = 'new string'
WHERE     Id = @fooId

答案 1 :(得分:0)

尝试这样的事情

public ActionResult Update(int id) 
{
    Foo foo = db.Foos.Find(id);
    foo.X = "new string";

    var entry = db.Entry(foo);
    entry.State = EntityState.Modified;

    db.SaveChanges();

    // Rest of code
}