Skip to content

Commit

Permalink
Audit.EntityFramework.Core: Fixing issue with Complex Type properties…
Browse files Browse the repository at this point in the history
… when using the EF DataProvider Property Matching (#697)
  • Loading branch information
thepirat000 committed Sep 25, 2024
1 parent e382cf6 commit 5760f6d
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 3 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ All notable changes to Audit.NET and its extensions will be documented in this f

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

## [27.0.3] - 2024-09-25:
- Audit.EntityFramework.Core: Fixing issue with Complex Type properties when using the EF DataProvider Property Matching (#697)

## [27.0.2] - 2024-09-18:
- Audit.NET.PostgreSql: Fixing issue with the PostgreSql data provider when using String data column (#695)

Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>27.0.2</Version>
<Version>27.0.3</Version>
<PackageReleaseNotes></PackageReleaseNotes>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
</PropertyGroup>
Expand Down
21 changes: 19 additions & 2 deletions src/Audit.EntityFramework/Providers/EntityFrameworkDataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,13 @@ private void SetAuditEntityMatchedProperties(Type definingType, EventEntry entry
var entity = entry.Entry.Entity;
var auditFields = GetPropertiesToSet(auditType);
var columnValues = entry.ColumnValues;

#if EF_CORE
var entityFields = entry.GetEntry().Metadata.GetProperties();
foreach (var prop in entityFields.Where(af => auditFields.ContainsKey(af.Name)))
// Map scalar properties
var entityProperties = entry.GetEntry().Metadata.GetProperties()
.Where(prop => auditFields.ContainsKey(prop.Name));

foreach (var prop in entityProperties)
{
var colName = DbContextHelper.GetColumnName(prop);
var value = columnValues.TryGetValue(colName, out var columnValue) ? columnValue : prop.PropertyInfo?.GetValue(entity);
Expand All @@ -326,6 +330,19 @@ private void SetAuditEntityMatchedProperties(Type definingType, EventEntry entry
auditFields[prop.Key].SetValue(auditEntity, value);
}
#endif

#if EF_CORE_8_OR_GREATER
// Map complex properties
var entityComplexProperties = entry.GetEntry().Metadata.GetComplexProperties()
.Where(prop => auditFields.ContainsKey(prop.Name));

foreach (var prop in entityComplexProperties)
{
var value = prop.PropertyInfo?.GetValue(entity);

auditFields[prop.Name].SetValue(auditEntity, value);
}
#endif
}

private Dictionary<string, PropertyInfo> GetPropertiesToSet(Type type)
Expand Down
14 changes: 14 additions & 0 deletions test/Audit.EntityFramework.Core.UnitTest/Contexts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,20 @@ public record Country
public string Alias { get; init; }
}

[AuditIgnore]
public class AuditLog
{
[Key]
public int AuditId { get; set; }
public string TableName { get; set; }
public string Action { get; set; }
[Required]
public Address Address { get; set; }
public string Name { get; set; }
}

public DbSet<Person> People { get; set; }
public DbSet<AuditLog> AuditLogs { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
Expand All @@ -51,6 +64,7 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>().ComplexProperty(e => e.Address).ComplexProperty(a => a.Country);
modelBuilder.Entity<AuditLog>().ComplexProperty(e => e.Address).ComplexProperty(a => a.Country);
}
}
#endif
Expand Down
68 changes: 68 additions & 0 deletions test/Audit.EntityFramework.Core.UnitTest/EfCoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ public void Setup()
new DemoContext().Database.EnsureCreated();
}

[OneTimeTearDown]
public void TearDown()
{
new BlogsContext().Database.EnsureDeleted();
new DemoContext().Database.EnsureDeleted();
}

#if EF_CORE_8_OR_GREATER
[Test]
public void Test_EF_ComplexType()
Expand Down Expand Up @@ -88,7 +95,62 @@ public void Test_EF_ComplexType()

Assert.That(evs[1].Entries[0].Changes.FirstOrDefault(ch => ch.ColumnName == "Address_Country_Alias")?.OriginalValue, Is.EqualTo("AU"));
Assert.That(evs[1].Entries[0].Changes.FirstOrDefault(ch => ch.ColumnName == "Address_Country_Alias")?.NewValue, Is.EqualTo("NEWALIAS"));

context.Database.EnsureDeleted();
}

[Test]
public void Test_EF_ComplexType_EntityFrameworkDataProvider_PropertyMatching()
{
// Arrange
Audit.Core.Configuration.Setup().UseEntityFramework(ef => ef
.AuditTypeExplicitMapper(m => m
.Map<Context_ComplexTypes.Person, Context_ComplexTypes.AuditLog>()
.AuditEntityAction<Context_ComplexTypes.AuditLog>((ev, entry, auditLog) =>
{
auditLog.TableName = entry.Table;
auditLog.Action = entry.Action;
}))
.IgnoreMatchedProperties(false));

using var context = new Context_ComplexTypes();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();

var name = Guid.NewGuid().ToString();
var city = "Rosario";
var alias = "alias";

// Act
var person = new Context_ComplexTypes.Person()
{
Id = 10,
Name = name,
Address = new Context_ComplexTypes.Address()
{
Country = new Context_ComplexTypes.Country() { Name = "Argentina", Alias = alias },
City = city,
Line1 = "Street",
PostCode = "1234"
}
};

context.People.Add(person);
context.SaveChanges();
var auditLogs = context.AuditLogs.ToList();

context.Database.EnsureDeleted();

// Assert
Assert.That(auditLogs, Has.Count.EqualTo(1));
Assert.That(auditLogs[0].Action, Is.EqualTo("Insert"));
Assert.That(auditLogs[0].Name, Is.EqualTo(name));
Assert.That(auditLogs[0].Address, Is.Not.Null);
Assert.That(auditLogs[0].Address.City, Is.EqualTo(city));
Assert.That(auditLogs[0].Address.Country, Is.Not.Null);
Assert.That(auditLogs[0].Address.Country.Alias, Is.EqualTo(alias));
}

#endif

#if EF_CORE_5_OR_GREATER
Expand Down Expand Up @@ -173,6 +235,8 @@ public void Test_EF_Core_ManyToMany_NoJoinEntity()
};
context.Posts.Add(post);
context.SaveChanges();

context.Database.EnsureDeleted();
}

Assert.That(evs.Count, Is.EqualTo(1));
Expand Down Expand Up @@ -246,6 +310,8 @@ public void Test_EF_Core_ManyToMany_NoJoinEntity_EFProvider()
Assert.True(context.Audit_PostTags.Any(pt => pt.TagsId == 101 && pt.PostsId == "10" && pt.Action == "Insert" && pt.Extra == "extra"));
Assert.True(context.Audit_PostTags.Any(pt => pt.TagsId == 102 && pt.PostsId == "10" && pt.Action == "Insert" && pt.Extra == "extra"));
Assert.True(context.Audit_PostTags.Any(pt => pt.TagsId == 101 && pt.PostsId == "10" && pt.Action == "Delete" && pt.Extra == "extra"));

context.Database.EnsureDeleted();
}

}
Expand Down Expand Up @@ -278,6 +344,8 @@ public void Test_EF_Core_OwnedSingleMultiple()
});

context.SaveChanges();

context.Database.EnsureDeleted();
}

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

0 comments on commit 5760f6d

Please sign in to comment.