Как известно, на вкладке "История" записываются действия, выполненные пользователями (в том числе и системными) при работе с сущностью, однако, конкретика изменения тех или иных реквизитов остается "за кадром". Чтобы конкретизировать, какой реквизит был изменен, и записать в историю значения до и после изменения - нужно немного дописать событие "До сохранения истории".
public override void BeforeSaveHistory(Sungero.Content.DocumentHistoryEventArgs e)
{
// Вызываем базовый обработчик
base.BeforeSaveHistory(e);
// Нам нужно записывать историю, только если произошло обновление
var isUpdateAction = e.Action == Sungero.CoreEntities.History.Action.Update;
if (!isUpdateAction)
return;
// Далее мы отбираем те свойства, для которых будем записывать данные в историю,
// нас не интересует некоторые системные свойства, и свойства-коллекции
var properties = _obj.State.Properties.Where(p =>
p != _obj.State.Properties.Index &&
p != _obj.State.Properties.Modified &&
p != _obj.State.Properties.DocumentDate &&
p != _obj.State.Properties.Versions &&
p != _obj.State.Properties.Tracking);
var propertiesType = Сontracts.Info.Properties.GetType();
var objType = _obj.GetType();
// Чтобы в истории, в колонке "Действие" отобразилось конкретное наименование - нам нужно
// создать Enumeration этого действия и создать под него строку локализации с префиксом
// Enum_Operation_ (для нашего примера - Enum_Operation_SDChange, где будет прописано желаемое
// имя действия, например "Изменение реквизита". Если этого не сделать - в колонке "Действие" будет пусто.
var operation = new Enumeration("SDChange");
// Обходим коллекцию свойств
foreach (var property in properties)
{
// Берем в работу только те свойства, которые были помечены как измененные
var isChanged = (property as Sungero.Domain.Shared.IPropertyState).IsChanged;
if (isChanged)
{
// Извлечение локализованного наименования реквизита.
var propertyName = (property as Sungero.Domain.Shared.PropertyStateBase).PropertyName;
var propertyInfo = propertiesType.GetProperty(propertyName).GetValue(Сontracts.Info.Properties);
var name = propertyInfo.GetType().GetProperty("LocalizedName").GetValue(propertyInfo);
// Извлечение нового значения реквизита.
var newValue = objType.GetProperty(propertyName).GetValue(_obj);
// Извлечение старого значения реквизита.
var oldValue = property.GetType().GetProperty("OriginalValue").GetValue(property);
// Дополнительно еще раз сверяет что старое и новое значения не равны, также отбрасываем изменения строковых свойств с null на пустую строку
if (newValue == oldValue ||
newValue != null && oldValue != null && Equals(newValue.ToString(), oldValue.ToString()) ||
newValue != null && oldValue == null && string.IsNullOrEmpty(newValue.ToString()) ||
oldValue != null && newValue == null && string.IsNullOrEmpty(oldValue.ToString()))
continue;
// Записываем данные в историю
var comment = string.Format("{0}. Новое значение: {1}. Прежнее значение: {2}", name, newValue, oldValue);
e.Write(operation, null, comment);
}
}
}
Таким образом в карточке сущности появится подробная детализация изменения данных сущности, что позволит отслеживать изменения более тщательно.
Добрый день. Есть 2 вопроса по представленному решению:
Александр, добрый день
1. В данном примере никак. Заказчику предложен вариант с информацией, что свойство-коллекция просто изменилось, без новых и прежних значений. И к каждому такому свойству приходится обращаться персонально
2. Спасибо за вопрос. В данном примере значение самого свойства. Не отображаемое имя, а само имя значения. Например для InternalApprovalState будет указано OnApproval, а не On approval или На согласовании.
Может кто подскажет как обратиться к типу свойства и в случае с перечислением к методу GetLocalizedValue. Или к свойоствам коллекции.
Александр, Денис.
Если автор не против, то я могу накидать статью с ответами на вопросы про Enumeration типы и коллекции, со ссылкой на Вашу статью.
Сергей, автор не будет против)
Подскажите, где конкретно и что надо создать чтобы вместо пустоты действия появился текст?
по комментарию так и не понял где искать это перечисление действий истории.
Станислав, Для операции SDChange необходимо создать ресурс в вашей карточке с префиксом Enum_Operation_
Добрый день!
Спасибо большое за сценарий!
Всё хорошо, но при получении свойств периодически подалась ошибка "Ambiguous match found".
Исправлена заменой
на
При желании можно также найти какой из нескольких найденных типов свойства больше подходит, но работает уже и так.
Авторизуйтесь, чтобы написать комментарий