diff --git a/CSM Database Core/CHANGELOG.md b/CSM Database Core/CHANGELOG.md index ce74d76..6da178a 100644 --- a/CSM Database Core/CHANGELOG.md +++ b/CSM Database Core/CHANGELOG.md @@ -1,5 +1,19 @@ # CSM Database Core CHANGELOG +## [6.0.4] - 18.06-2026 + +### Fixes + +- Fixed [DepotBase] [Update] method issue that was causing not relation inclussion on original entity object. + +#### Dependencies + +| Package | Previous Version | New Version | +|:----------------------------------------|:----------------:|:---------------:| +| CSM.Foundation.Core | 4.0.0 | 4.0.0 | +| Microsoft.EntityFrameworkCore | 10.0.8 | 10.0.9 | +| Microsoft.EntityFrameworkCore.SqlServer | 10.0.8 | 10.0.9 | + ## [6.0.3] - 18.06-2026 ### Fixes diff --git a/CSM Database Core/CSM Database Core.csproj b/CSM Database Core/CSM Database Core.csproj index f941bf8..b2e3328 100644 --- a/CSM Database Core/CSM Database Core.csproj +++ b/CSM Database Core/CSM Database Core.csproj @@ -4,7 +4,7 @@ net10.0 CSM_Database_Core CSM.Database.Core - 6.0.3 + 6.0.4 Renato Urrea Cosmos (CSM) https://github.com/Cosmos-CSM/csm_database diff --git a/CSM Database Core/Depots/Abstractions/Bases/DepotBase.cs b/CSM Database Core/Depots/Abstractions/Bases/DepotBase.cs index 761fadb..7083ecf 100644 --- a/CSM Database Core/Depots/Abstractions/Bases/DepotBase.cs +++ b/CSM Database Core/Depots/Abstractions/Bases/DepotBase.cs @@ -274,9 +274,15 @@ public async Task> Update(QueryInput query = _dbSet; - originalEntity = await query - .Where(obj => obj.Id == updateEntity.Id) - .AsNoTracking() + IQueryable ogEntityQuery = query + .AsNoTrackingWithIdentityResolution() + .Where(obj => obj.Id == updateEntity.Id); + + if (input.PostProcessor != null) { + ogEntityQuery = input.PostProcessor(ogEntityQuery); + } + + originalEntity = await ogEntityQuery .FirstOrDefaultAsync(); // --> When the update entity comes with ID, but there was no enitty stored with that ID, we check if creation is valid. diff --git a/DatabaseProxy/Entities/EntityProxy.cs b/DatabaseProxy/Entities/EntityProxy.cs index d18b76c..af1d99c 100644 --- a/DatabaseProxy/Entities/EntityProxy.cs +++ b/DatabaseProxy/Entities/EntityProxy.cs @@ -27,7 +27,8 @@ protected override void DesignEntity(EntityTypeBuilder etBuilder) { etBuilder.Link( nameof(EntityDependencyProxy), targetRef: nameof(EntityDependencyProxy.EntityProxies), - isAutoLoaded: true + isAutoLoaded: true, + deleteBehavior: Microsoft.EntityFrameworkCore.DeleteBehavior.Cascade ); } } diff --git a/DatabaseProxy/Migrations/20260619050113_IncludingCascadingDeletion.Designer.cs b/DatabaseProxy/Migrations/20260619050113_IncludingCascadingDeletion.Designer.cs new file mode 100644 index 0000000..6240d32 --- /dev/null +++ b/DatabaseProxy/Migrations/20260619050113_IncludingCascadingDeletion.Designer.cs @@ -0,0 +1,126 @@ +// +using System; +using DatabaseProxy; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace DatabaseProxy.Migrations +{ + [DbContext(typeof(DatabaseProxy))] + [Migration("20260619050113_IncludingCascadingDeletion")] + partial class IncludingCascadingDeletion + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("DatabaseProxy.Entities.EntityDependantProxy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("EntityProxyShadow") + .HasColumnType("bigint") + .HasColumnName("EntityProxy"); + + b.Property("Timestamp") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2(7)") + .HasDefaultValueSql("GETUTCDATE()"); + + b.HasKey("Id"); + + b.HasIndex("EntityProxyShadow"); + + b.ToTable("EntityDependantProxies"); + }); + + modelBuilder.Entity("DatabaseProxy.Entities.EntityDependencyProxy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Timestamp") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2(7)") + .HasDefaultValueSql("GETUTCDATE()"); + + b.HasKey("Id"); + + b.ToTable("EntityDependencyProxies"); + }); + + modelBuilder.Entity("DatabaseProxy.Entities.EntityProxy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("EntityDependencyProxyShadow") + .HasColumnType("bigint") + .HasColumnName("EntityDependencyProxy"); + + b.Property("Timestamp") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2(7)") + .HasDefaultValueSql("GETUTCDATE()"); + + b.HasKey("Id"); + + b.HasIndex("EntityDependencyProxyShadow"); + + b.ToTable("EntityProxies"); + }); + + modelBuilder.Entity("DatabaseProxy.Entities.EntityDependantProxy", b => + { + b.HasOne("DatabaseProxy.Entities.EntityProxy", "EntityProxy") + .WithMany("EntityDependantProxies") + .HasForeignKey("EntityProxyShadow") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("EntityProxy"); + }); + + modelBuilder.Entity("DatabaseProxy.Entities.EntityProxy", b => + { + b.HasOne("DatabaseProxy.Entities.EntityDependencyProxy", "EntityDependencyProxy") + .WithMany("EntityProxies") + .HasForeignKey("EntityDependencyProxyShadow") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("EntityDependencyProxy"); + }); + + modelBuilder.Entity("DatabaseProxy.Entities.EntityDependencyProxy", b => + { + b.Navigation("EntityProxies"); + }); + + modelBuilder.Entity("DatabaseProxy.Entities.EntityProxy", b => + { + b.Navigation("EntityDependantProxies"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DatabaseProxy/Migrations/20260619050113_IncludingCascadingDeletion.cs b/DatabaseProxy/Migrations/20260619050113_IncludingCascadingDeletion.cs new file mode 100644 index 0000000..1b5d885 --- /dev/null +++ b/DatabaseProxy/Migrations/20260619050113_IncludingCascadingDeletion.cs @@ -0,0 +1,42 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DatabaseProxy.Migrations +{ + /// + public partial class IncludingCascadingDeletion : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_EntityProxies_EntityDependencyProxies_EntityDependencyProxy", + table: "EntityProxies"); + + migrationBuilder.AddForeignKey( + name: "FK_EntityProxies_EntityDependencyProxies_EntityDependencyProxy", + table: "EntityProxies", + column: "EntityDependencyProxy", + principalTable: "EntityDependencyProxies", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_EntityProxies_EntityDependencyProxies_EntityDependencyProxy", + table: "EntityProxies"); + + migrationBuilder.AddForeignKey( + name: "FK_EntityProxies_EntityDependencyProxies_EntityDependencyProxy", + table: "EntityProxies", + column: "EntityDependencyProxy", + principalTable: "EntityDependencyProxies", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + } + } +} diff --git a/DatabaseProxy/Migrations/DatabaseProxyModelSnapshot.cs b/DatabaseProxy/Migrations/DatabaseProxyModelSnapshot.cs index 4da0a61..30523af 100644 --- a/DatabaseProxy/Migrations/DatabaseProxyModelSnapshot.cs +++ b/DatabaseProxy/Migrations/DatabaseProxyModelSnapshot.cs @@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "10.0.5") + .HasAnnotation("ProductVersion", "10.0.9") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -103,7 +103,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasOne("DatabaseProxy.Entities.EntityDependencyProxy", "EntityDependencyProxy") .WithMany("EntityProxies") .HasForeignKey("EntityDependencyProxyShadow") - .OnDelete(DeleteBehavior.Restrict); + .OnDelete(DeleteBehavior.Cascade); b.Navigation("EntityDependencyProxy"); }); diff --git a/Integration Tests/Tests/DepotBaseTests.cs b/Integration Tests/Tests/DepotBaseTests.cs index c04da43..838cd52 100644 --- a/Integration Tests/Tests/DepotBaseTests.cs +++ b/Integration Tests/Tests/DepotBaseTests.cs @@ -29,8 +29,12 @@ protected override EntityProxy EntityFactory(string Entropy) { public override async Task Update_Single_Success() { //Expectation EntityProxy testEntity = await Store( - new EntityProxy() - ); + new EntityProxy { + + } + ); + + EntityDependencyProxy dependency = await Store( new EntityDependencyProxy() ); @@ -38,6 +42,13 @@ public override async Task Update_Single_Success() { EntityDependantProxy dependant = await Store( new EntityDependantProxy() ); + + await Store( + new EntityDependantProxy { + EntityProxy = testEntity + } + ); + testEntity.EntityDependencyProxy = dependency; UpdateOutput updateOutput = await _depot.Update( @@ -62,17 +73,22 @@ public override async Task Update_Single_Success() { } ); - Assert.NotNull(updateOutput.Original); - Assert.Empty(updateOutput.Original.EntityDependantProxies); - Assert.NotEmpty(updateOutput.Updated.EntityDependantProxies); + EntityProxy? ogEntity = updateOutput.Original; + EntityProxy updatedEntity = updateOutput.Updated; + + + Assert.NotNull(ogEntity); + Assert.Single(ogEntity.EntityDependantProxies); + + Assert.NotEmpty(updatedEntity.EntityDependantProxies); Assert.Contains( - updateOutput.Updated.EntityDependantProxies, + updatedEntity.EntityDependantProxies, (dependantEntry) => dependantEntry.Id == dependant.Id ); Assert.Equal( dependency.Id, - updateOutput.Updated.EntityDependencyProxy.Id + updatedEntity.EntityDependencyProxy.Id ); } }