Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
dotnet-version: [9.x]
dotnet-version: [10.x]
services:
mssql:
image: mcr.microsoft.com/mssql/server:2019-latest
Expand Down
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<Authors>Tony Sneed</Authors>
<Company>Tony Sneed</Company>
<NoWarn>$(NoWarn);CS1591</NoWarn>
Expand All @@ -12,7 +12,7 @@
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageReleaseNotes>
https://github.com/TrackableEntities/TrackableEntities.Core/releases/tag/v9.0.0
https://github.com/TrackableEntities/TrackableEntities.Core/releases/tag/v10.0.0
</PackageReleaseNotes>
</PropertyGroup>

Expand Down
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Change-tracking across service boundaries with [ASP.NET Core](https://docs.micro

## Installation

Trackable Entities for EF Core 9 is available as a NuGet package that can be installed in an ASP.NET Core Web API project that uses Entity Framework Core.
Trackable Entities for EF Core 10 is available as a NuGet package that can be installed in an ASP.NET Core Web API project that uses Entity Framework Core.

You can use the [Package Manager UI or Console](https://docs.microsoft.com/en-us/nuget/tools/package-manager-console) in Visual Studio to install the TE package.

Expand All @@ -28,7 +28,17 @@ dotnet add package TrackableEntities.EF.Core

## Packages for Previous Versions of EntityFramework Core

##### [EntityFramework Core v8](https://www.nuget.org/packages/TrackableEntities.EF.Core/8.0.0) | [EntityFramework Core v7](https://www.nuget.org/packages/TrackableEntities.EF.Core/7.0.0) | [EntityFramework Core v6](https://www.nuget.org/packages/TrackableEntities.EF.Core/6.0.0) | [EntityFramework Core v5](https://www.nuget.org/packages/TrackableEntities.EF.Core/5.0.1) | [EntityFramework Core v3](https://www.nuget.org/packages/TrackableEntities.EF.Core/3.1.1)
##### [EntityFramework Core v9](https://www.nuget.org/packages/TrackableEntities.EF.Core/9.0.1) | [EntityFramework Core v8](https://www.nuget.org/packages/TrackableEntities.EF.Core/8.0.0) | [EntityFramework Core v7](https://www.nuget.org/packages/TrackableEntities.EF.Core/7.0.0) | [EntityFramework Core v6](https://www.nuget.org/packages/TrackableEntities.EF.Core/6.0.0) | [EntityFramework Core v5](https://www.nuget.org/packages/TrackableEntities.EF.Core/5.0.1) | [EntityFramework Core v3](https://www.nuget.org/packages/TrackableEntities.EF.Core/3.1.1)

## EF Core 10 Behavior Changes

EF Core 10 includes a change in entity state validation that affects how Trackable Entities handles certain edge cases:

- **Deleted parent with Added children**: In EF Core 9 and earlier, attempting to delete an entity that had children marked as `Added` would throw an `InvalidOperationException`. EF Core 10 relaxes this validation and allows the operation to proceed.

- **Impact**: If you previously relied on receiving an exception when accidentally marking a parent as `Deleted` while its children were marked as `Added`, this validation is no longer enforced by EF Core. The operation will now proceed, and the child entities will be set to `Deleted` along with their parent.

- **Recommendation**: Ensure your client-side logic properly validates entity state combinations before sending object graphs to the server. Avoid marking parent entities as `Deleted` when child entities are marked as `Added`, as this represents a logical contradiction (you cannot delete a parent while simultaneously adding new children to it).


## Trackable Entities Interfaces
Expand Down
17 changes: 14 additions & 3 deletions TrackableEntities.EF.Core.Tests/NorthwindDbContextTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -850,13 +850,24 @@ public void Apply_Changes_Should_Mark_Unchanged_Order_Deleted_Customer_With_Addr
Customer = order.Customer
};
order.Customer.CustomerAddresses = new List<CustomerAddress> { address1, address2 };
address1.TrackingState = TrackingState.Added;
address2.TrackingState = TrackingState.Added;
order.Customer.TrackingState = TrackingState.Deleted;

// Act / Assert
Exception ex = Assert.Throws<InvalidOperationException>(() => context.ApplyChanges(order));
// Act
// Note: When navigating from Order (many side) to Customer (one side), the Customer's
// Deleted state is overridden to Unchanged since the Customer may be related to other entities.
// However, the Customer's TrackingState property is still Deleted, so when processing
// child entities (CustomerAddresses), they are set to Deleted based on the parent's TrackingState.
context.ApplyChanges(order);

// Assert
Assert.Equal(Constants.ExceptionMessages.DeletedWithAddedChildren, ex.Message);
Assert.Equal(EntityState.Unchanged, context.Entry(order).State);
// Customer is set to Unchanged because it's reached via OneToMany navigation from Order
Assert.Equal(EntityState.Unchanged, context.Entry(order.Customer).State);
// Addresses are set to Deleted because parent's TrackingState is Deleted (even though parent EntityState is Unchanged)
Assert.Equal(EntityState.Deleted, context.Entry(address1).State);
Assert.Equal(EntityState.Deleted, context.Entry(address2).State);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
Expand Down
10 changes: 1 addition & 9 deletions TrackableEntities.EF.Core/DbContextExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,7 @@ public static void ApplyChanges(this DbContext context, ITrackable item)
if (node.SourceEntry.State == EntityState.Deleted
|| parent?.TrackingState == TrackingState.Deleted)
{
try
{
// Will throw if there are added children
SetEntityState(node.Entry, TrackingState.Deleted.ToEntityState(), trackable);
}
catch (InvalidOperationException e)
{
throw new InvalidOperationException(Constants.ExceptionMessages.DeletedWithAddedChildren, e);
}
SetEntityState(node.Entry, TrackingState.Deleted.ToEntityState(), trackable);
return;
}
break;
Expand Down
2 changes: 1 addition & 1 deletion TrackableEntities.EF.Core/TrackableEntities.EF.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down