现在,我的代码看起来就像这样简单:
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。当我继续运行该程序时,更新成功完成。起初我觉得这很奇怪。也许存在低级别竞争条件(我说低级别是因为我没有在应用程序级别执行任何异步/线程)并且断点允许其他线程赶上。也就是说,直到我再次使用断点运行更新without将鼠标悬停在 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;
}
}