Я пытаюсь найти идеальный способ обработки этого исключения и заставить изменения клиента перезаписывать любые другие изменения, вызвавшие конфликт. Подход, который я предложил, заключается в том, чтобы заключить вызов Session.Transaction.Commit()
в цикл, внутри цикла я бы сделал блок try-catch и обработал каждый устаревший объект индивидуально, скопировав его свойства, кроме свойства row-version, а затем обновив объект, чтобы получить последние данные БД, затем скопировать исходные значения в обновленный объект и затем выполнить слияние. Как только я зациклюсь, я выполню фиксацию, и если произойдет какое-либо другое StaleObjectStateException
, то применимо то же самое. Цикл продолжается до тех пор, пока все конфликты не будут разрешены.
Этот метод является частью класса UnitOfWork. Чтобы было понятнее, я выложу свой код:
// 'Client-wins' rules, any conflicts found will always cause client changes to
// overwrite anything else.
public void CommitAndRefresh() {
bool saveFailed;
do {
try {
_session.Transaction.Commit();
_session.BeginTransaction();
saveFailed = false;
} catch (StaleObjectStateException ex) {
saveFailed = true;
// Get the staled object with client changes
var staleObject = _session.Get(ex.EntityName, ex.Identifier);
// Extract the row-version property name
IClassMetadata meta = _sessionFactory.GetClassMetadata(ex.EntityName);
string rowVersionPropertyName = meta.PropertyNames[meta.VersionProperty] as string;
// Store all property values from client changes
var propertyValues = new Dictionary<string, object>();
var publicProperties = staleObject.GetType().GetProperties();
foreach (var p in publicProperties) {
if (p.Name != rowVersionPropertyName) {
propertyValues.Add(p.Name, p.GetValue(staleObject, null));
}
}
// Get latest data for staled object from the database
_session.Refresh(staleObject);
// Update the data with the original client changes except for row-version
foreach (var p in publicProperties) {
if (p.Name != rowVersionPropertyName) {
p.SetValue(staleObject, propertyValues[p.Name], null);
}
}
// Merge
_session.Merge(staleObject);
}
} while (saveFailed);
}
Приведенный выше код работает нормально и обрабатывает параллелизм с правилом client-wins. Однако мне было интересно, есть ли в NHibernate какие-либо встроенные возможности, чтобы сделать это для меня, или есть лучший способ справиться с этим.
Заранее спасибо,