В Entity Framework v1 есть возможность подписаться на событие SavingChanges. Это событие вызывается перед записью в базу когда вызывается метод SaveChanges. Чтобы получить все измененные записи в контексте необходимо обратиться к свойству ObjectStateManager контекста и вызвать его метод GetObjectStateEntries.

Ниже приведен код partial класса контекста, который сохраняет изменения сущностей.

 

   1: partial void OnContextCreated()
   2: {
   3:     this.SavingChanges += new EventHandler(AuditLogHandler);
   4: }
   5:  
   6: void AuditLogHandler(object sender, EventArgs _)
   7: {
   8:     var entries = this.ObjectStateManager
   9:                       .GetObjectStateEntries(EntityState.Added 
  10:                                            | EntityState.Deleted 
  11:                                            | EntityState.Modified)
  12:                       .Where(e => !e.IsRelationship)
  13:                       .ToList()
  14:                       ;
  15:  
  16:     var tranId = Guid.NewGuid();
  17:     var now = DateTime.Now;
  18:  
  19:     var logEntries = from e in entries
  20:                      select new AuditLogEntry
  21:                      {
  22:                          TableName = e.EntitySet.Name,
  23:                          Action = (byte)e.State,
  24:                          Time = now,
  25:                          TransactionId = tranId,   
  26:                          Key = KeyToString(e.EntityKey),
  27:                          Values = StateEntryToXml(e)
  28:                      };
  29:     SaveLog(logEntries);
  30: }
  31:  
  32: string KeyToString(EntityKey key)
  33: {
  34:     if (key == null || key.IsTemporary)
  35:     {
  36:         return null;
  37:     }
  38:     if (key.EntityKeyValues.Length == 1)
  39:     {
  40:         return key.EntityKeyValues[0].Value.ToString();
  41:     }
  42:     else
  43:     {
  44:         return string.Join("; ",
  45:                    key.EntityKeyValues
  46:                       .Select(k => k.Key + "=" + k.Value)
  47:                       .ToArray());
  48:     }
  49: }
  50:  
  51: private string StateEntryToXml(ObjectStateEntry e)
  52: {
  53:     switch (e.State)
  54:     {
  55:         case EntityState.Added:
  56:             var count = e.CurrentValues.FieldCount;
  57:             return new XElement("Values",
  58:                        from i in Enumerable.Range(0, count)
  59:                        select new XElement("Value",
  60:                            new XAttribute("Name",
  61:                                e.CurrentValues.GetName(i)),
  62:                            e.CurrentValues.GetValue(i)))
  63:                    .ToString();
  64:         case EntityState.Deleted:
  65:             return null;
  66:         case EntityState.Modified:
  67:             return new XElement("Values",
  68:                        from v in e.GetModifiedProperties()
  69:                        let ord = e.OriginalValues.GetOrdinal(v)
  70:                        select new XElement("Value",
  71:                            new XAttribute("Name", v),
  72:                            new XAttribute("Old",
  73:                                e.OriginalValues.GetValue(ord)),
  74:                            e.CurrentValues.GetValue(ord)))
  75:                    .ToString();
  76:         default:
  77:             throw new InvalidOperationException();
  78:     }
  79: }

Таким же способом можно поддерживать Row-Level Security при обновлении данных с помощью EF.

Теги : .NET, Entity Framework