Кажется, прямо переопределить SaveChanges в EF, чтобы добавить регистратор аудита. См. метод ApplyAuditLogging для установки свойств аудита (создано, создано, обновлено, обновлено) ниже.
public override int SaveChanges()
{
var autoDetectChanges = Configuration.AutoDetectChangesEnabled;
try
{
Configuration.AutoDetectChangesEnabled = false;
ChangeTracker.DetectChanges();
var errors = GetValidationErrors().ToList();
if(errors.Any())
{
throw new DbEntityValidationException("Validation errors were found during save: " + errors);
}
foreach (var entry in ChangeTracker.Entries().Where(e => e.State == EntityState.Added || e.State == EntityState.Modified))
{
ApplyAuditLogging(entry);
}
ChangeTracker.DetectChanges();
Configuration.ValidateOnSaveEnabled = false;
return base.SaveChanges();
}
finally
{
Configuration.AutoDetectChangesEnabled = autoDetectChanges;
}
}
private static void ApplyAuditLogging(DbEntityEntry entityEntry)
{
var logger = entityEntry.Entity as IAuditLogger;
if (logger == null) return;
var currentValue = entityEntry.Cast<IAuditLogger>().Property(p => p.Audit).CurrentValue;
if (currentValue == null) currentValue = new Audit();
currentValue.Updated = DateTime.Now;
currentValue.UpdatedBy = "???????????????????????";
if(entityEntry.State == EntityState.Added)
{
currentValue.Created = DateTime.Now;
currentValue.CreatedBy = "????????????????????????";
}
}
Проблема в том, что как получить логин/имя пользователя Windows для установки свойств UpdatedBy и CreatedBy объекта? Поэтому я не мог использовать это!
Кроме того, в другом случае я хотел автоматически добавить новую запись CallHistory в свой контакт; всякий раз, когда контакт изменяется, необходимо добавить новую запись в дочернюю таблицу CallHistory. Поэтому я сделал это в InsertOrUpdate репозитория, но это кажется грязным, было бы неплохо, если бы я мог сделать это на более высоком уровне, так как теперь мне нужно установить текущего пользователя из базы данных. Опять же, проблема в том, что мне нужно получить пользователя из базы данных, чтобы создать запись CallHistory (SalesRep = User).
Код в моем репозитории теперь делает 2 вещи: 1) он создает запись аудита для объекта при его создании или обновлении и 2) он также создает запись CallHistory всякий раз, когда контакт обновляется:
ContactRepository.SetCurrentUser(User).InsertOrUpdate(contact)
Чтобы иметь пользователя в контексте репозитория для:
var prop = typeof(T).GetProperty("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
if (prop.GetValue(entity, null).ToString() == "0")
{
// New entity
_context.Set<T>().Add(entity);
var auditLogger = entity as IAuditLogger;
if (auditLogger != null)
auditLogger.Audit = new Audit(true, _principal.Identity.Name);
}
else
{
// Existing entity
_context.Entry(entity).State = EntityState.Modified;
var auditLogger = entity as IAuditLogger;
if (auditLogger != null && auditLogger.Audit != null)
{
(entity as IAuditLogger).Audit.Updated = DateTime.Now;
(entity as IAuditLogger).Audit.UpdatedBy = _principal.Identity.Name;
}
var contact = entity as Contact;
if (_currentUser != null)
contact.CallHistories.Add(new CallHistory
{
CallTime = DateTime.Now,
Contact = contact,
Created = DateTime.Now,
CreatedBy = _currentUser.Logon,
SalesRep = _currentUser
});
}
}
Есть ли способ как-то внедрить пользователя Windows в переопределение SaveChanges в DbContext, а также есть ли способ получить пользователя из базы данных на основе идентификатора входа в Windows, чтобы я мог установить SalesRep в моей CallHistory (см. код выше)?
Вот мое действие на контроллере в приложении MVC:
[HttpPost]
public ActionResult Create([Bind(Prefix = "Contact")]Contact contact, FormCollection collection)
{
SetupVOs(collection, contact, true);
SetupBuyingProcesses(collection, contact, true);
var result = ContactRepository.Validate(contact);
Validate(result);
if (ModelState.IsValid)
{
ContactRepository.SetCurrentUser(User).InsertOrUpdate(contact);
ContactRepository.Save();
return RedirectToAction("Edit", "Contact", new {id = contact.Id});
}
var viewData = LoadContactControllerCreateViewModel(contact);
SetupPrefixDropdown(viewData, contact);
return View(viewData);
}