Skip to content

Commit a6a0303

Browse files
update source
1 parent a298c0e commit a6a0303

38 files changed

+1140
-93
lines changed

src/shared/Z.EF.Plus.Audit.Shared/Audit/AuditEntityAdded.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,17 @@ public partial class Audit
3232
#if EF5 || EF6
3333
public static void AuditEntityAdded(Audit audit, ObjectStateEntry objectStateEntry)
3434
#elif EFCORE
35-
public static void AuditEntityAdded(Audit audit, EntityEntry objectStateEntry)
35+
public static void AuditEntityAdded(Audit audit, EntityEntry objectStateEntry, DbContext context)
3636
#endif
3737
{
3838
var entry = audit.Configuration.AuditEntryFactory != null ?
3939
audit.Configuration.AuditEntryFactory(new AuditEntryFactoryArgs(audit, objectStateEntry, AuditEntryState.EntityAdded)) :
4040
new AuditEntry();
41-
41+
#if EF5 || EF6
4242
entry.Build(audit, objectStateEntry);
43+
#elif EFCORE
44+
entry.Build(audit, objectStateEntry, context);
45+
#endif
4346
entry.State = AuditEntryState.EntityAdded;
4447

4548
audit.Entries.Add(entry);

src/shared/Z.EF.Plus.Audit.Shared/Audit/AuditEntityDeleted.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,17 @@ public partial class Audit
3030
#if EF5 || EF6
3131
public static void AuditEntityDeleted(Audit audit, ObjectStateEntry objectStateEntry)
3232
#elif EFCORE
33-
public static void AuditEntityDeleted(Audit audit, EntityEntry objectStateEntry)
33+
public static void AuditEntityDeleted(Audit audit, EntityEntry objectStateEntry, DbContext context)
3434
#endif
3535
{
3636
var entry = audit.Configuration.AuditEntryFactory != null ?
3737
audit.Configuration.AuditEntryFactory(new AuditEntryFactoryArgs(audit, objectStateEntry, AuditEntryState.EntityDeleted)) :
3838
new AuditEntry();
39-
39+
#if EF5 || EF6
4040
entry.Build(audit, objectStateEntry);
41+
#elif EFCORE
42+
entry.Build(audit, objectStateEntry, context);
43+
#endif
4144
entry.State = AuditEntryState.EntityDeleted;
4245

4346
audit.Entries.Add(entry);

src/shared/Z.EF.Plus.Audit.Shared/Audit/AuditEntityModified.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,18 @@ public partial class Audit
3030
#if EF5 || EF6
3131
public static void AuditEntityModified(Audit audit, ObjectStateEntry objectStateEntry, AuditEntryState state)
3232
#elif EFCORE
33-
public static void AuditEntityModified(Audit audit, EntityEntry objectStateEntry, AuditEntryState state)
33+
public static void AuditEntityModified(Audit audit, EntityEntry objectStateEntry, AuditEntryState state, DbContext context)
3434
#endif
3535
{
3636
var entry = audit.Configuration.AuditEntryFactory != null ?
3737
audit.Configuration.AuditEntryFactory(new AuditEntryFactoryArgs(audit, objectStateEntry, state)) :
3838
new AuditEntry();
3939

40+
#if EF5 || EF6
4041
entry.Build(audit, objectStateEntry);
42+
#elif EFCORE
43+
entry.Build(audit, objectStateEntry, context);
44+
#endif
4145
entry.State = state;
4246

4347
#if EF5 || EF6
@@ -139,7 +143,7 @@ public static void AuditEntityModified(Audit audit, AuditEntry entry, EntityEntr
139143

140144
if (property.Metadata.IsKey() || entry.Parent.CurrentOrDefaultConfiguration.IsAuditedProperty(entry.Entry, propertyEntry.Name))
141145
{
142-
if (!audit.Configuration.IgnorePropertyUnchanged || property.Metadata.IsKey() || property.IsModified)
146+
if (!audit.Configuration.IgnorePropertyUnchanged || property.Metadata.IsKey() || !Equals(property.CurrentValue, property.OriginalValue))
143147
{
144148
var auditEntryProperty = entry.Parent.Configuration.AuditEntryPropertyFactory != null ?
145149
entry.Parent.Configuration.AuditEntryPropertyFactory(new AuditEntryPropertyArgs(entry, objectStateEntry, propertyEntry.Name, property.OriginalValue, property.CurrentValue)) :
@@ -149,7 +153,7 @@ public static void AuditEntityModified(Audit audit, AuditEntry entry, EntityEntr
149153
auditEntryProperty.IsKey = property.Metadata.IsKey();
150154
entry.Properties.Add(auditEntryProperty);
151155

152-
if (property.IsModified)
156+
if (!property.Metadata.IsKey())
153157
{
154158
hasModified = true;
155159
}

src/shared/Z.EF.Plus.Audit.Shared/Audit/PostSaveChanges.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ public static void PostSaveChanges(Audit audit)
8888
#endif
8989
break;
9090
}
91+
92+
if (audit.Configuration.MetaProperties != null)
93+
{
94+
foreach (var metaProperty in audit.Configuration.MetaProperties)
95+
{
96+
metaProperty(entry);
97+
}
98+
}
9199
}
92100
// foreach (var entry in audit.Entries)
93101
// {

src/shared/Z.EF.Plus.Audit.Shared/Audit/PreSaveChanges.cs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -89,19 +89,28 @@ public static void PreSaveChanges(Audit audit, DbContext context)
8989
&& !audit.CurrentOrDefaultConfiguration.IgnoreEntityAdded
9090
&& audit.CurrentOrDefaultConfiguration.IsAuditedEntity(objectStateEntry))
9191
{
92-
AuditEntityAdded(audit, objectStateEntry);
93-
}
92+
#if EF5 || EF6
93+
AuditEntityAdded(audit, objectStateEntry);
94+
#elif EFCORE
95+
AuditEntityAdded(audit, objectStateEntry, context);
96+
#endif
97+
}
9498

95-
// Entity Deleted
96-
else if (objectStateEntry.State == EntityState.Deleted
99+
// Entity Deleted
100+
else if (objectStateEntry.State == EntityState.Deleted
97101
&& !audit.CurrentOrDefaultConfiguration.IgnoreEntityDeleted
98102
&& audit.CurrentOrDefaultConfiguration.IsAuditedEntity(objectStateEntry))
99103
{
104+
#if EF5 || EF6
100105
AuditEntityDeleted(audit, objectStateEntry);
106+
#elif EFCORE
107+
AuditEntityDeleted(audit, objectStateEntry, context);
108+
#endif
109+
101110
}
102111

103-
// Entity Modified
104-
else if (objectStateEntry.State == EntityState.Modified
112+
// Entity Modified
113+
else if (objectStateEntry.State == EntityState.Modified
105114
&& audit.CurrentOrDefaultConfiguration.IsAuditedEntity(objectStateEntry))
106115
{
107116
var auditState = audit.CurrentOrDefaultConfiguration.GetEntityModifiedState(objectStateEntry);
@@ -110,23 +119,35 @@ public static void PreSaveChanges(Audit audit, DbContext context)
110119
if (auditState == AuditEntryState.EntityModified
111120
&& !audit.CurrentOrDefaultConfiguration.IgnoreEntityModified)
112121
{
122+
#if EF5 || EF6
113123
AuditEntityModified(audit, objectStateEntry, auditState);
114-
}
124+
#elif EFCORE
125+
AuditEntityModified(audit, objectStateEntry, auditState, context);
126+
#endif
127+
}
115128

116-
// Entity Soft Added
117-
else if (auditState == AuditEntryState.EntitySoftAdded
129+
// Entity Soft Added
130+
else if (auditState == AuditEntryState.EntitySoftAdded
118131
&& !audit.CurrentOrDefaultConfiguration.IgnoreEntitySoftAdded)
119132
{
133+
#if EF5 || EF6
120134
AuditEntityModified(audit, objectStateEntry, auditState);
135+
#elif EFCORE
136+
AuditEntityModified(audit, objectStateEntry, auditState, context);
137+
#endif
121138
}
122139

123-
// Entity Soft Deleted
124-
else if (auditState == AuditEntryState.EntitySoftDeleted
140+
// Entity Soft Deleted
141+
else if (auditState == AuditEntryState.EntitySoftDeleted
125142
&& !audit.CurrentOrDefaultConfiguration.IgnoreEntitySoftDeleted)
126143
{
144+
#if EF5 || EF6
127145
AuditEntityModified(audit, objectStateEntry, auditState);
146+
#elif EFCORE
147+
AuditEntityModified(audit, objectStateEntry, auditState, context);
148+
#endif
128149
}
129-
}
150+
}
130151
#if EF5 || EF6
131152
}
132153
#endif

src/shared/Z.EF.Plus.Audit.Shared/AuditConfiguration.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public AuditConfiguration()
4242
IsAuditedDictionary = new ConcurrentDictionary<string, bool>();
4343
ValueFormatterDictionary = new ConcurrentDictionary<string, Func<object, object>>();
4444

45+
MetaProperties = new List<Action<AuditEntry>>();
4546

4647
#if EF5 || EF6
4748
UseNullForDBNullValue = true;
@@ -75,6 +76,8 @@ public AuditConfiguration()
7576
/// <value>A list of predicates to exclude or include properties.</value>
7677
public List<Func<object, string, bool?>> ExcludeIncludePropertyPredicates { get; set; }
7778

79+
public List<Action<AuditEntry>> MetaProperties { get; set; }
80+
7881
/// <summary>Gets or sets a value indicating whether the entity with Added state are audited.</summary>
7982
/// <value>true if entity with Added state are audited, false if not.</value>
8083
public bool IgnoreEntityAdded { get; set; }
@@ -179,6 +182,7 @@ public AuditConfiguration Clone()
179182
ExcludeIncludePropertyPredicates = new List<Func<object, string, bool?>>(ExcludeIncludePropertyPredicates),
180183
SoftAddedPredicates = new List<Func<object, bool>>(SoftAddedPredicates),
181184
SoftDeletedPredicates = new List<Func<object, bool>>(SoftDeletedPredicates),
185+
MetaProperties = new List<Action<AuditEntry>>(MetaProperties),
182186
ExcludeRelationshipIfOneExcluded = ExcludeRelationshipIfOneExcluded,
183187
UseUtcDateTime = UseUtcDateTime,
184188
IgnorePropertyAdded = IgnorePropertyAdded,

src/shared/Z.EF.Plus.Audit.Shared/AuditConfiguration/FormatType.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ public AuditConfiguration FormatType<T>(Func<T, object> formatter)
3333
#else
3434
Func<object, object> func = o => formatter((T) o);
3535
#endif
36-
EntityValueFormatters.Add((x, s, v) => v != null && v.GetType() == typeof(T) ? func : null);
36+
EntityValueFormatters.Add((x, s, v) => v != null && (v.GetType() == typeof(T) ||
37+
(
38+
typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>) && v.GetType() == typeof(T).GetGenericArguments()[0]
39+
)) ? func : null);
3740

3841
return this;
3942
}

src/shared/Z.EF.Plus.Audit.Shared/AuditConfiguration/FormatValue.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,17 @@ public string FormatValue(object entity, string propertyName, object currentValu
3939
if (entity != null && EntityValueFormatters.Count > 0)
4040
{
4141
var type = entity.GetType();
42-
var key = string.Concat(type.FullName, ";", propertyName);
42+
// Null value doesn't work with scenario 2. So we add it to the key for this scenario.
43+
// Only scenario 2 use the currentValue
44+
// 1. EntityValueFormatters.Add((x, s, v) => x is T && s == accessor ? formatter : null);
45+
// 2. EntityValueFormatters.Add((x, s, v) => v != null && v.GetType() == typeof(T) ? func : null);
46+
var key = string.Concat(type.FullName, ";", propertyName, ";", currentValue == null ? "NULL" : currentValue.GetType().FullName);
4347
Func<object, object> formatter;
4448

4549
if (!ValueFormatterDictionary.TryGetValue(key, out formatter))
4650
{
4751
if (EntityValueFormatters.Count > 0)
48-
{
52+
{
4953
foreach (var formatProperty in EntityValueFormatters)
5054
{
5155
formatter = formatProperty(entity, propertyName, currentValue);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Description: Entity Framework Bulk Operations & Utilities (EF Bulk SaveChanges, Insert, Update, Delete, Merge | LINQ Query Cache, Deferred, Filter, IncludeFilter, IncludeOptimize | Audit)
2+
// Website & Documentation: https://github.com/zzzprojects/Entity-Framework-Plus
3+
// Forum & Issues: https://github.com/zzzprojects/EntityFramework-Plus/issues
4+
// License: https://github.com/zzzprojects/EntityFramework-Plus/blob/master/LICENSE
5+
// More projects: http://www.zzzprojects.com/
6+
// Copyright © ZZZ Projects Inc. 2014 - 2016. All rights reserved.
7+
8+
using System;
9+
10+
namespace Z.EntityFramework.Plus
11+
{
12+
public partial class AuditConfiguration
13+
{
14+
public AuditConfiguration MetaProperty<T>(string propertyName, Func<T, object> oldValueFactory, Func<T, object> newValueFactory)
15+
{
16+
MetaProperties.Add(auditEntry =>
17+
{
18+
if (auditEntry.Entity != null && auditEntry.Entity is T)
19+
{
20+
auditEntry.Properties.Add(new AuditEntryProperty
21+
{
22+
Parent = auditEntry,
23+
PropertyName = propertyName,
24+
OldValue = oldValueFactory?.Invoke((T) auditEntry.Entity),
25+
NewValue = newValueFactory?.Invoke((T) auditEntry.Entity)
26+
});
27+
}
28+
});
29+
30+
return this;
31+
}
32+
}
33+
}

src/shared/Z.EF.Plus.Audit.Shared/AuditEntry.cs

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
using System.Data.Entity.Core.Objects;
1717

1818
#elif EFCORE
19+
using Microsoft.EntityFrameworkCore;
1920
using Microsoft.EntityFrameworkCore.ChangeTracking;
21+
using System.Collections.Concurrent;
22+
using System.Linq;
2023

2124
#endif
2225

@@ -25,10 +28,14 @@ namespace Z.EntityFramework.Plus
2528
/// <summary>An audit entry.</summary>
2629
public class AuditEntry
2730
{
31+
#if EFCORE
32+
public static ConcurrentDictionary<Type, ConcurrentDictionary<Type, string>> DictEntitySetNameByContext = new ConcurrentDictionary<Type, ConcurrentDictionary<Type, string>>();
33+
#endif
34+
2835
#if EF5 || EF6
2936
public void Build(Audit parent, ObjectStateEntry entry)
3037
#else
31-
public void Build(Audit parent, EntityEntry entry)
38+
public void Build(Audit parent, EntityEntry entry, DbContext context)
3239
#endif
3340
{
3441
if (CreatedBy == null)
@@ -83,7 +90,43 @@ public void Build(Audit parent, EntityEntry entry)
8390
#elif EFCORE
8491
if (EntityTypeName == null)
8592
{
86-
EntityTypeName = Entry.Entity.GetType().Name;
93+
EntityTypeName = parent.CurrentOrDefaultConfiguration.EntityNameFactory != null ?
94+
parent.CurrentOrDefaultConfiguration.EntityNameFactory(Entry.Entity.GetType()) : Entry.Entity.GetType().Name;
95+
}
96+
97+
if (EntitySetName == null)
98+
{
99+
var dictEntitySetNameByTypes = DictEntitySetNameByContext.GetOrAdd(context.GetType(), new ConcurrentDictionary<Type, string>());
100+
var entitySetName = dictEntitySetNameByTypes.GetOrAdd(Entry.Entity.GetType(), type =>
101+
{
102+
try
103+
{
104+
string setName = null;
105+
var setProperties = context.GetDbSetProperties();
106+
var baseType = Entry.Entity.GetType();
107+
108+
while (baseType != typeof(object))
109+
{
110+
// If we found more than one corresponding entry, we throw an error and stop searching
111+
var setSingle = setProperties.SingleOrDefault(x => x.PropertyType.GetGenericArguments()[0] == Entry.Entity.GetType());
112+
if (setSingle != null)
113+
{
114+
setName = setSingle.Name;
115+
break;
116+
}
117+
118+
baseType = baseType.BaseType;
119+
}
120+
121+
return setName;
122+
}
123+
catch
124+
{
125+
return null;
126+
}
127+
});
128+
129+
EntitySetName = entitySetName;
87130
}
88131
#endif
89132
}

0 commit comments

Comments
 (0)