我目前有一个这样的对象(简化):
public class Image {
public int Id { get; set; }
public int ExternalId { get; set; }
}
现在让我说我有这种方法(主要是伪代码):
public void GetImage(int externalId) {
var existingImage = db.Images.FirstOrDefault(i => i.ExternalId == externalId);
if (existingImage != null) {
return existingImage;
}
var newImage = new Image() { ExternalId = externalId };
db.Images.Attach(newImage);
db.SaveChanges();
return newImage;
}
由于ExternalId不是密钥,因此更改跟踪器无需关心跟踪器中是否有“重复”图像。
现在,让我们说这个方法被调用两次,同时通过AJAX和Web API(我当前的场景)。它是异步的,所以现在有两个线程调用这个方法。
如果调用之间的时间足够短(在我的情况下),则将使用相同的外部ID向数据库添加两行,因为现有检查都不会返回一行。我已经大大简化了这个例子,因为在我的实例中,当我从服务中获取“图像”时会出现计时问题。
我该怎样防止这种情况?无论是新的还是更新的,我都需要返回图像。我在数据库中添加了一个Unique Constraint,所以我得到了一个例外,但是在客户端上,调用失败了,而应使用现有的图像而不是抛出异常。
如果我正确理解EF,我可以通过使ExternalId
成为主键然后使用并发来处理这个来解决这个问题,对吗?有没有办法避免更改我当前的模型或这是唯一的选择?
答案 0 :(得分:1)
如果您已经拥有定义实体唯一性的属性(ExternalId
),则应将其用作密钥,而不是创建另一个未指定实体唯一性的虚拟密钥。如果不使用ExternalId
作为键,则必须对数据库中的该列设置唯一约束,并在代码中处理异常以从数据库加载现有Image
。