Entity Framework по умолчанию использует оптимистическую модель параллелизма. Google говорит, что оптимизм означает « с надеждой и уверенностью в будущем », и именно так действует Entity Framework. То есть, когда вы звоните SaveChanges()
, это означает " с надеждой и уверенностью ", что проблема параллелизма не возникнет, поэтому он просто пытается сохранить ваши изменения.
Другая модель, которую может использовать Entity Framework, должна называться пессимистической моделью параллелизма (" с ожиданием худшего возможного результата "). Вы можете включить этот режим для каждого объекта. В вашем случае вы бы включили его на объекте App . Вот что я делаю:
Шаг 1. Включение проверки параллельности для сущности
- Щелкните правой кнопкой мыши файл .edmx и выберите Открыть с помощью ...
- Выберите XML (Text) Editor во всплывающем диалоговом окне и нажмите OK.
Найдите сущность приложения в ConceptualModels . Я предлагаю переключать контуры и просто расширять теги по мере необходимости. Вы ищете что-то вроде этого:
<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 , чтобы вернуться к представлению конструктора.
Шаг 2. Обработка параллелизма при вызове SaveChanges()
SaveChanges()
выдаст одно из двух исключений. Знакомая UpdateException или OptimisticConcurrencyException .
Если вы внесли изменения в Entity, для которого установлено значение ConcurrencyMode="Fixed"
, Entity Framework сначала проверит хранилище данных на наличие изменений, внесенных в него. Если есть изменения, будет выброшено OptimisticConcurrencyException
. Если не было внесено никаких изменений, оно продолжится в обычном режиме.
Когда вы ловите OptimisticConcurrencyException
, вам нужно вызвать Refresh () метод вашего ObjectContext
и повторить ваш расчет, прежде чем пытаться снова. Вызов Refresh()
обновляет сущность (и), а RefreshMode.StoreWins
означает, что конфликты будут разрешаться с использованием данных в хранилище данных. Одновременное изменение DownloadCount является конфликтом.
Вот как я бы сделал ваш код похожим. Обратите внимание, что это более полезно, когда у вас много операций между получением вашей сущности и вызовом 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...
}
}