From 1567f7fa0d3ec6a11eafd8b2ee47aabeab03269f Mon Sep 17 00:00:00 2001 From: Federico Colombo Date: Wed, 14 Dec 2022 15:37:30 -0600 Subject: [PATCH] Fixing issue with GetColumnName when a property is mapped to JSON using EF Core 7 (#555) --- CHANGELOG.md | 3 + Directory.Build.props | 2 +- .../Audit.EntityFramework.Core.csproj | 2 +- ...Audit.EntityFramework.Identity.Core.csproj | 2 +- .../DbContextHelper.Core.cs | 7 +- ...Audit.EntityFramework.Core.UnitTest.csproj | 2 +- .../Contexts.cs | 34 ++++++++ .../EfCoreInMemoryTests.cs | 82 +++++++++++++++++++ 8 files changed, 129 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50d5a455..e74f27ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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/). +## [20.1.2] - 2022-12-14 +- Audit.EntityFramework.Core: Fixing issue with GetColumnName when a property is mapped to JSON using EF Core 7 (#555) + ## [20.1.1] - 2022-12-12 - Audit.Mvc: Adding `IncludeChildActions` configuration to the `AuditAttribute` action filter for MVC 5 (#554) diff --git a/Directory.Build.props b/Directory.Build.props index dcf82c8f..7e27fce7 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 20.1.1 + 20.1.2 diff --git a/src/Audit.EntityFramework.Core/Audit.EntityFramework.Core.csproj b/src/Audit.EntityFramework.Core/Audit.EntityFramework.Core.csproj index 4834c2cd..2464f560 100644 --- a/src/Audit.EntityFramework.Core/Audit.EntityFramework.Core.csproj +++ b/src/Audit.EntityFramework.Core/Audit.EntityFramework.Core.csproj @@ -41,7 +41,7 @@ $(DefineConstants);EF_CORE_6;EF_CORE_2_OR_GREATER;EF_CORE_3_OR_GREATER;EF_CORE_5_OR_GREATER;EF_CORE_6_OR_GREATER - $(DefineConstants);EF_CORE_7;EF_CORE_2_OR_GREATER;EF_CORE_3_OR_GREATER;EF_CORE_5_OR_GREATER;EF_CORE_6_OR_GREATER + $(DefineConstants);EF_CORE_7;EF_CORE_2_OR_GREATER;EF_CORE_3_OR_GREATER;EF_CORE_5_OR_GREATER;EF_CORE_6_OR_GREATER;EF_CORE_7_OR_GREATER diff --git a/src/Audit.EntityFramework.Identity.Core/Audit.EntityFramework.Identity.Core.csproj b/src/Audit.EntityFramework.Identity.Core/Audit.EntityFramework.Identity.Core.csproj index 94d088f1..ded900a6 100644 --- a/src/Audit.EntityFramework.Identity.Core/Audit.EntityFramework.Identity.Core.csproj +++ b/src/Audit.EntityFramework.Identity.Core/Audit.EntityFramework.Identity.Core.csproj @@ -59,7 +59,7 @@ - $(DefineConstants);EF_CORE_7;EF_CORE_2_OR_GREATER;EF_CORE_3_OR_GREATER;EF_CORE_5_OR_GREATER;EF_CORE_6_OR_GREATER + $(DefineConstants);EF_CORE_7;EF_CORE_2_OR_GREATER;EF_CORE_3_OR_GREATER;EF_CORE_5_OR_GREATER;EF_CORE_6_OR_GREATER;EF_CORE_7_OR_GREATER diff --git a/src/Audit.EntityFramework/DbContextHelper.Core.cs b/src/Audit.EntityFramework/DbContextHelper.Core.cs index 56365fb7..c8876ecb 100644 --- a/src/Audit.EntityFramework/DbContextHelper.Core.cs +++ b/src/Audit.EntityFramework/DbContextHelper.Core.cs @@ -49,7 +49,12 @@ private List GetChanges(IAuditDbContext context, EntityEntry e /// private static string GetColumnName(IProperty prop) { -#if EF_CORE_5_OR_GREATER +#if EF_CORE_7_OR_GREATER + var storeObjectIdentifier = StoreObjectIdentifier.Create(prop.DeclaringEntityType, StoreObjectType.Table); + return storeObjectIdentifier.HasValue + ? (prop.GetColumnName(storeObjectIdentifier.Value) ?? prop.GetDefaultColumnName()) + : prop.GetDefaultColumnName(); +#elif EF_CORE_5_OR_GREATER var storeObjectIdentifier = StoreObjectIdentifier.Create(prop.DeclaringEntityType, StoreObjectType.Table); return storeObjectIdentifier.HasValue ? prop.GetColumnName(storeObjectIdentifier.Value) diff --git a/test/Audit.EntityFramework.Core.UnitTest/Audit.EntityFramework.Core.UnitTest.csproj b/test/Audit.EntityFramework.Core.UnitTest/Audit.EntityFramework.Core.UnitTest.csproj index 9a733256..c7eb6a06 100644 --- a/test/Audit.EntityFramework.Core.UnitTest/Audit.EntityFramework.Core.UnitTest.csproj +++ b/test/Audit.EntityFramework.Core.UnitTest/Audit.EntityFramework.Core.UnitTest.csproj @@ -37,7 +37,7 @@ - $(DefineConstants);EF_CORE_7;EF_CORE_2_OR_GREATER;EF_CORE_3_OR_GREATER;EF_CORE_5_OR_GREATER;EF_CORE_6_OR_GREATER + $(DefineConstants);EF_CORE_7;EF_CORE_2_OR_GREATER;EF_CORE_3_OR_GREATER;EF_CORE_5_OR_GREATER;EF_CORE_6_OR_GREATER;EF_CORE_7_OR_GREATER diff --git a/test/Audit.EntityFramework.Core.UnitTest/Contexts.cs b/test/Audit.EntityFramework.Core.UnitTest/Contexts.cs index 24970904..348fafca 100644 --- a/test/Audit.EntityFramework.Core.UnitTest/Contexts.cs +++ b/test/Audit.EntityFramework.Core.UnitTest/Contexts.cs @@ -4,6 +4,40 @@ namespace Audit.EntityFramework.Core.UnitTest { +#if EF_CORE_7_OR_GREATER + [AuditDbContext(IncludeEntityObjects = true)] + public class Context_OwnedEntity_ToJson : AuditDbContext + { + public class Person + { + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public int Id { get; set; } + public string Name { get; set; } + public Address Address { get; set; } + } + public class Address + { + public string City { get; set; } + public string Street { get; set; } + } + + public DbSet People { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (!optionsBuilder.IsConfigured) + { + optionsBuilder.UseSqlServer(@$"Server=(localdb)\mssqllocaldb;Database={nameof(Context_OwnedEntity_ToJson)};Trusted_Connection=True;ConnectRetryCount=0").UseLazyLoadingProxies(); + } + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().OwnsOne(e => e.Address, b => b.ToJson()); + } + } +#endif + #if EF_CORE_5_OR_GREATER [AuditDbContext(IncludeEntityObjects = true)] public class Context_OwnedEntity : AuditDbContext diff --git a/test/Audit.EntityFramework.Core.UnitTest/EfCoreInMemoryTests.cs b/test/Audit.EntityFramework.Core.UnitTest/EfCoreInMemoryTests.cs index 385bba19..3e200331 100644 --- a/test/Audit.EntityFramework.Core.UnitTest/EfCoreInMemoryTests.cs +++ b/test/Audit.EntityFramework.Core.UnitTest/EfCoreInMemoryTests.cs @@ -24,6 +24,88 @@ public void Setup() Audit.Core.Configuration.ResetCustomActions(); } +#if EF_CORE_7_OR_GREATER + [Test] + public void Test_EF_OwnedEntity_ToJson() + { + using var context = new Context_OwnedEntity_ToJson(); + var evs = new List(); + Audit.Core.Configuration.Setup() + .UseDynamicProvider(_ => _.OnInsertAndReplace(ev => + { + evs.Add(ev.GetEntityFrameworkEvent()); + })); + + context.Database.EnsureDeleted(); + context.Database.EnsureCreated(); + + context.People.Add(new Context_OwnedEntity_ToJson.Person() + { + Id = 1, + Name = "Development", + Address = new Context_OwnedEntity_ToJson.Address { City = "Vienna", Street = "Street" }, + }); + + context.SaveChanges(); + + Assert.AreEqual(1, evs.Count); + + Assert.AreEqual(2, evs[0].Entries.Count); + + Assert.AreEqual("Insert", evs[0].Entries[0].Action); + Assert.AreEqual("Insert", evs[0].Entries[1].Action); + + Assert.AreEqual(1, evs[0].Entries[0].ColumnValues["Id"]); + Assert.AreEqual("Development", evs[0].Entries[0].ColumnValues["Name"]); + + Assert.AreEqual("Vienna", evs[0].Entries[1].ColumnValues["City"]); + Assert.AreEqual("Street", evs[0].Entries[1].ColumnValues["Street"]); + + Assert.AreEqual(1, ((dynamic)evs[0].Entries[0].Entity).Id); + Assert.AreEqual("Vienna", ((dynamic)evs[0].Entries[0].Entity).Address.City); + } + + [Test] + public async Task Test_EF_OwnedEntity_ToJson_Async() + { + using var context = new Context_OwnedEntity_ToJson(); + var evs = new List(); + Audit.Core.Configuration.Setup() + .UseDynamicProvider(_ => _.OnInsertAndReplace(ev => + { + evs.Add(ev.GetEntityFrameworkEvent()); + })); + + await context.Database.EnsureDeletedAsync(); + await context.Database.EnsureCreatedAsync(); + + await context.People.AddAsync(new Context_OwnedEntity_ToJson.Person() + { + Id = 1, + Name = "Development", + Address = new Context_OwnedEntity_ToJson.Address { City = "Vienna", Street = "Street" }, + }); + + await context.SaveChangesAsync(); + + Assert.AreEqual(1, evs.Count); + + Assert.AreEqual(2, evs[0].Entries.Count); + + Assert.AreEqual("Insert", evs[0].Entries[0].Action); + Assert.AreEqual("Insert", evs[0].Entries[1].Action); + + Assert.AreEqual(1, evs[0].Entries[0].ColumnValues["Id"]); + Assert.AreEqual("Development", evs[0].Entries[0].ColumnValues["Name"]); + + Assert.AreEqual("Vienna", evs[0].Entries[1].ColumnValues["City"]); + Assert.AreEqual("Street", evs[0].Entries[1].ColumnValues["Street"]); + + Assert.AreEqual(1, ((dynamic)evs[0].Entries[0].Entity).Id); + Assert.AreEqual("Vienna", ((dynamic)evs[0].Entries[0].Entity).Address.City); + } +#endif + [Test] public void Test_EF_SaveChangesGetAudit() {