Skip to content

Commit 5760f6d

Browse files
author
thepirat000
committed
Audit.EntityFramework.Core: Fixing issue with Complex Type properties when using the EF DataProvider Property Matching (#697)
1 parent e382cf6 commit 5760f6d

File tree

5 files changed

+105
-3
lines changed

5 files changed

+105
-3
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ All notable changes to Audit.NET and its extensions will be documented in this f
33

44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
55

6+
## [27.0.3] - 2024-09-25:
7+
- Audit.EntityFramework.Core: Fixing issue with Complex Type properties when using the EF DataProvider Property Matching (#697)
8+
69
## [27.0.2] - 2024-09-18:
710
- Audit.NET.PostgreSql: Fixing issue with the PostgreSql data provider when using String data column (#695)
811

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>27.0.2</Version>
3+
<Version>27.0.3</Version>
44
<PackageReleaseNotes></PackageReleaseNotes>
55
<CheckEolTargetFramework>false</CheckEolTargetFramework>
66
</PropertyGroup>

src/Audit.EntityFramework/Providers/EntityFrameworkDataProvider.cs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,13 @@ private void SetAuditEntityMatchedProperties(Type definingType, EventEntry entry
310310
var entity = entry.Entry.Entity;
311311
var auditFields = GetPropertiesToSet(auditType);
312312
var columnValues = entry.ColumnValues;
313+
313314
#if EF_CORE
314-
var entityFields = entry.GetEntry().Metadata.GetProperties();
315-
foreach (var prop in entityFields.Where(af => auditFields.ContainsKey(af.Name)))
315+
// Map scalar properties
316+
var entityProperties = entry.GetEntry().Metadata.GetProperties()
317+
.Where(prop => auditFields.ContainsKey(prop.Name));
318+
319+
foreach (var prop in entityProperties)
316320
{
317321
var colName = DbContextHelper.GetColumnName(prop);
318322
var value = columnValues.TryGetValue(colName, out var columnValue) ? columnValue : prop.PropertyInfo?.GetValue(entity);
@@ -326,6 +330,19 @@ private void SetAuditEntityMatchedProperties(Type definingType, EventEntry entry
326330
auditFields[prop.Key].SetValue(auditEntity, value);
327331
}
328332
#endif
333+
334+
#if EF_CORE_8_OR_GREATER
335+
// Map complex properties
336+
var entityComplexProperties = entry.GetEntry().Metadata.GetComplexProperties()
337+
.Where(prop => auditFields.ContainsKey(prop.Name));
338+
339+
foreach (var prop in entityComplexProperties)
340+
{
341+
var value = prop.PropertyInfo?.GetValue(entity);
342+
343+
auditFields[prop.Name].SetValue(auditEntity, value);
344+
}
345+
#endif
329346
}
330347

331348
private Dictionary<string, PropertyInfo> GetPropertiesToSet(Type type)

test/Audit.EntityFramework.Core.UnitTest/Contexts.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,20 @@ public record Country
3737
public string Alias { get; init; }
3838
}
3939

40+
[AuditIgnore]
41+
public class AuditLog
42+
{
43+
[Key]
44+
public int AuditId { get; set; }
45+
public string TableName { get; set; }
46+
public string Action { get; set; }
47+
[Required]
48+
public Address Address { get; set; }
49+
public string Name { get; set; }
50+
}
51+
4052
public DbSet<Person> People { get; set; }
53+
public DbSet<AuditLog> AuditLogs { get; set; }
4154

4255
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
4356
{
@@ -51,6 +64,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
5164
protected override void OnModelCreating(ModelBuilder modelBuilder)
5265
{
5366
modelBuilder.Entity<Person>().ComplexProperty(e => e.Address).ComplexProperty(a => a.Country);
67+
modelBuilder.Entity<AuditLog>().ComplexProperty(e => e.Address).ComplexProperty(a => a.Country);
5468
}
5569
}
5670
#endif

test/Audit.EntityFramework.Core.UnitTest/EfCoreTests.cs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ public void Setup()
3030
new DemoContext().Database.EnsureCreated();
3131
}
3232

33+
[OneTimeTearDown]
34+
public void TearDown()
35+
{
36+
new BlogsContext().Database.EnsureDeleted();
37+
new DemoContext().Database.EnsureDeleted();
38+
}
39+
3340
#if EF_CORE_8_OR_GREATER
3441
[Test]
3542
public void Test_EF_ComplexType()
@@ -88,7 +95,62 @@ public void Test_EF_ComplexType()
8895

8996
Assert.That(evs[1].Entries[0].Changes.FirstOrDefault(ch => ch.ColumnName == "Address_Country_Alias")?.OriginalValue, Is.EqualTo("AU"));
9097
Assert.That(evs[1].Entries[0].Changes.FirstOrDefault(ch => ch.ColumnName == "Address_Country_Alias")?.NewValue, Is.EqualTo("NEWALIAS"));
98+
99+
context.Database.EnsureDeleted();
91100
}
101+
102+
[Test]
103+
public void Test_EF_ComplexType_EntityFrameworkDataProvider_PropertyMatching()
104+
{
105+
// Arrange
106+
Audit.Core.Configuration.Setup().UseEntityFramework(ef => ef
107+
.AuditTypeExplicitMapper(m => m
108+
.Map<Context_ComplexTypes.Person, Context_ComplexTypes.AuditLog>()
109+
.AuditEntityAction<Context_ComplexTypes.AuditLog>((ev, entry, auditLog) =>
110+
{
111+
auditLog.TableName = entry.Table;
112+
auditLog.Action = entry.Action;
113+
}))
114+
.IgnoreMatchedProperties(false));
115+
116+
using var context = new Context_ComplexTypes();
117+
context.Database.EnsureDeleted();
118+
context.Database.EnsureCreated();
119+
120+
var name = Guid.NewGuid().ToString();
121+
var city = "Rosario";
122+
var alias = "alias";
123+
124+
// Act
125+
var person = new Context_ComplexTypes.Person()
126+
{
127+
Id = 10,
128+
Name = name,
129+
Address = new Context_ComplexTypes.Address()
130+
{
131+
Country = new Context_ComplexTypes.Country() { Name = "Argentina", Alias = alias },
132+
City = city,
133+
Line1 = "Street",
134+
PostCode = "1234"
135+
}
136+
};
137+
138+
context.People.Add(person);
139+
context.SaveChanges();
140+
var auditLogs = context.AuditLogs.ToList();
141+
142+
context.Database.EnsureDeleted();
143+
144+
// Assert
145+
Assert.That(auditLogs, Has.Count.EqualTo(1));
146+
Assert.That(auditLogs[0].Action, Is.EqualTo("Insert"));
147+
Assert.That(auditLogs[0].Name, Is.EqualTo(name));
148+
Assert.That(auditLogs[0].Address, Is.Not.Null);
149+
Assert.That(auditLogs[0].Address.City, Is.EqualTo(city));
150+
Assert.That(auditLogs[0].Address.Country, Is.Not.Null);
151+
Assert.That(auditLogs[0].Address.Country.Alias, Is.EqualTo(alias));
152+
}
153+
92154
#endif
93155

94156
#if EF_CORE_5_OR_GREATER
@@ -173,6 +235,8 @@ public void Test_EF_Core_ManyToMany_NoJoinEntity()
173235
};
174236
context.Posts.Add(post);
175237
context.SaveChanges();
238+
239+
context.Database.EnsureDeleted();
176240
}
177241

178242
Assert.That(evs.Count, Is.EqualTo(1));
@@ -246,6 +310,8 @@ public void Test_EF_Core_ManyToMany_NoJoinEntity_EFProvider()
246310
Assert.True(context.Audit_PostTags.Any(pt => pt.TagsId == 101 && pt.PostsId == "10" && pt.Action == "Insert" && pt.Extra == "extra"));
247311
Assert.True(context.Audit_PostTags.Any(pt => pt.TagsId == 102 && pt.PostsId == "10" && pt.Action == "Insert" && pt.Extra == "extra"));
248312
Assert.True(context.Audit_PostTags.Any(pt => pt.TagsId == 101 && pt.PostsId == "10" && pt.Action == "Delete" && pt.Extra == "extra"));
313+
314+
context.Database.EnsureDeleted();
249315
}
250316

251317
}
@@ -278,6 +344,8 @@ public void Test_EF_Core_OwnedSingleMultiple()
278344
});
279345

280346
context.SaveChanges();
347+
348+
context.Database.EnsureDeleted();
281349
}
282350

283351
Assert.That(evs.Count, Is.EqualTo(1));

0 commit comments

Comments
 (0)