默认情况下,实体框架使用乐观并发模型。谷歌表示乐观意味着“对未来充满希望和信心”,而这正是 Entity Framework 的行为方式。也就是说,当您称它为SaveChanges()
“充满希望和自信”时,不会发生并发问题,因此它只是尝试保存您的更改。
Entity Framework 可以使用的另一种模型应该称为悲观并发模型(“期望最坏的结果”)。您可以逐个实体启用此模式。在您的情况下,您将在App实体上启用它。这就是我所做的:
步骤 1. 对实体启用并发检查
- 右键单击.edmx文件并选择打开方式...
- 在弹出对话框中选择XML (Text) Editor ,然后单击 OK。
在ConceptualModels中找到 App 实体。我建议切换大纲并根据需要扩展标签。你正在寻找这样的东西:
<edmx:Edmx Version="2.0" xmlns:edmx="http://schemas.microsoft.com/ado/2008/10/edmx">
<!-- EF Runtime content -->
<edmx:Runtime>
<!-- SSDL content -->
...
<!-- CSDL content -->
<edmx:ConceptualModels>
<Schema Namespace="YourModel" Alias="Self" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
<EntityType Name="App">
在 EntityType 下,您应该会看到一堆<Property>
标签。如果存在Name="Status"
通过添加修改它ConcurrencyMode="Fixed"
。如果该属性不存在,请将其复制到:
<Property Name="Status" Type="Byte" Nullable="false" ConcurrencyMode="Fixed" />
保存文件并双击.edmx文件以返回设计器视图。
Step 2. 调用时的并发处理SaveChanges()
SaveChanges()
将抛出两个异常之一。熟悉的UpdateException或OptimisticConcurrencyException。
如果您对已ConcurrencyMode="Fixed"
设置的实体进行了更改,实体框架将首先检查数据存储是否对其进行了任何更改。如果有更改,OptimisticConcurrencyException
将抛出 a。如果没有进行任何更改,它将正常继续。
当您捕获时,OptimisticConcurrencyException
您需要调用Refresh()方法ObjectContext
并重做计算,然后再重试。Refresh()
更新实体的调用RefreshMode.StoreWins
意味着将使用数据存储中的数据解决冲突。同时更改的 DownloadCount 是一个冲突。
这就是我要让你的代码看起来像的样子。请注意,当您在获取 Entity 和调用 之间有很多操作时,这会更有用SaveChanges()
。
private void IncreaseHitCountDB()
{
JTF.JTFContainer jtfdb = new JTF.JTFContainer();
var app =
(from a in jtfdb.Apps
where a.Name.Equals(this.Title)
select a).FirstOrDefault();
if (app == null)
{
app = new JTF.App();
app.Name = this.Title;
app.DownloadCount = 1;
jtfdb.AddToApps(app);
}
else
{
app.DownloadCount = app.DownloadCount + 1;
}
try
{
try
{
jtfdb.SaveChanges();
}
catch (OptimisticConcurrencyException)
{
jtfdb.Refresh(RefreshMode.StoreWins, app);
app.DownloadCount = app.DownloadCount + 1;
jtfdb.SaveChanges();
}
}
catch (UpdateException uex)
{
// Something else went wrong...
}
}