В 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.