现在,我的代码看起来很简单:
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;
}
}
答案 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
}