2

У меня есть контроллер OAP данных WebAPI, который использует Delta для частичного обновления моего объекта.Как вы используете оптимистичный параллелизм с контроллером OAP для WebAPI

В моей модели структуры сущности у меня есть поле Version. Это rowversion в базе данных SQL Server и сопоставляется с массивом байтов в Entity Framework с режимом параллелизма, установленным в Fixed (сначала используется база данных).

Я использую fiddler для отправки частичного обновления с использованием устаревшего значения для поля Version. Я загружаю текущую запись из своего контекста, а затем я исправляю мои измененные поля сверху, что изменяет значения в столбце «Версия», не вызывая ошибки, а затем, когда я сохраняю изменения в моем контексте, все сохраняется без ошибок. Очевидно, что ожидается, что объект, который сохраняется, не был удален из контекста, так как я могу реализовать оптимистичный параллелизм с Delta.

Я использую самые последние версии всего (или было как раз перед Рождеством), так Entity Framework 6.0.1 и 5.6.0 OData

public IHttpActionResult Put([FromODataUri]int key, [FromBody]Delta<Job> delta) 
{ 
    using (var tran = new TransactionScope()) 
    { 
     Job j = this._context.Jobs.SingleOrDefault(x => x.JobId == key); 

     delta.Patch(j); 

     this._context.SaveChanges(); 

     tran.Complete(); 

     return Ok(j); 
    } 
} 

Благодарности

ответ

0

Простой, как вы всегда сделайте это с помощью Entity Framework: вы добавите поле Timestamp и поместите это поле Concurrency Mode в Fixed. Это гарантирует, что EF знает, что это временное поле не является частью каких-либо запросов, а используется для определения версий.

Смотрите также http://blogs.msdn.com/b/alexj/archive/2009/05/20/tip-19-how-to-use-optimistic-concurrency-in-the-entity-framework.aspx

+0

К сожалению, это не исправление. Он работает только в том случае, если запись изменяется в течение очень короткого промежутка времени между Post PostFromCtx1 = ctx1.Post.First (p => p.ID == 1); 'и' ctx1.SaveChanges(); '. Это фактически описано как анти-шаблон здесь: http://msdn.microsoft.com/en-us/magazine/dd882522.aspx. В моем сценарии «bob» загружает v1 записи, «jane» затем обновляет запись до v2, а через 20 минут «bob» пытается сохранить свой v1, который будет успешным. – BenCr

+0

Тогда вам придется выполнять проверки параллелизма самостоятельно. Когда Боб пытается сохранить свой v1, он не добьется успеха, потому что обновление Джейн изменит метку времени от первоначального значения, которое удерживает Боб. –

+0

Использование моего кода в вопросе Обновление Боба всегда преуспевает (за исключением очень редкого случая, когда два обновления происходят в секунду), потому что он загружает v2, а затем применяет его изменения к нему, поэтому контекст всегда обновляет свежий объект. Я предполагаю, что вопрос в том, как я сам реализую проверки параллелизма в этом «отключенном» сценарии. – BenCr

0

Когда Вы отправляете данные на сервер, вам необходимо отправить RowVersion поле, а также. Если вы тестируете его с помощью скрипача, получите последнее значение RowVersion из своей базы данных и добавьте его в Request Body.

Должно быть что-то типа;

RowVersion: "AAAAAAAAB9E=" 

Если это веб-страница, в то время как вы загружаете данные с сервера, снова получить RowVersion поле от сервера, держать его в скрытом поле и отправить его обратно на сервер вместе с другими изменениями.

В принципе, когда вы вызываете PATCH метод, RowField должен быть в вашем patch объекте.

Затем обновите свой код следующим образом;

Job j = this._context.Jobs.SingleOrDefault(x => x.JobId == key); 

// Concurrency check 
if (!j.RowVersion.SequenceEqual(patch.GetEntity().RowVersion)) 
{ 
    return Conflict(); 
} 

this._context.Entry(entity).State = EntityState.Modified; // Probably you need this line as well? 
this._context.SaveChanges(); 
3

Я просто столкнулся с этим с использованием контроллеров Entity Framework 6 и Web API 2 OData.

EF DbContext, похоже, использует исходное значение метки времени, полученной, когда объект был загружен в начале методов PUT/PATCH для проверки параллелизма при последующем обновлении.

Обновление текущего значения временной метки до значения, отличного от значения в базе данных перед сохранением изменений, не приводит к ошибке параллелизма.

Я обнаружил, что вы можете «исправить» это поведение, заставив исходное значение метки времени быть текущим в контексте.

Например, вы можете сделать это, переопределив SaveChanges в контексте, например.:

public partial class DataContext 
{ 
    public override int SaveChanges() 
    { 
     foreach (DbEntityEntry<Job> entry in ChangeTracker.Entries<Job>().Where(u => u.State == EntityState.Modified)) 
      entry.Property("Timestamp").OriginalValue = entry.Property("Timestamp").CurrentValue; 

     return base.SaveChanges(); 
    } 
} 

(Предполагая, что столбец параллелизма называется «Отметка» и режим параллелизма для этого столбца установлен значением «Fixed» в EDMX)

Дальнейшее усовершенствование этого было бы написать и применить пользовательский интерфейс для всех ваших моделей, требующих этого исправления, и просто замените «Job» интерфейсом в приведенном выше коде.

Обратная связь от Rowan в Рамочной группы Entity (4 августа 2015):

Это дизайн. В некоторых случаях вполне корректно обновлять токен параллелизма , и в этом случае нам нужно текущее значение для хранения значения , которое должно быть установлено, а исходное значение должно содержать значение , которое мы должны проверить. Например, вы можете настроить Person.LastName как токен параллелизма. Это один из минусов шаблона «запрос и обновление», который используется в этом действии.

Логика Вы добавили, чтобы установить правильное исходное значение, это правильный подход к использованию в этом сценарии.

+1

Записан с командой Entity Framework: https://entityframework.codeplex.com/workitem/2789 – bambam