diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index a927291..f73ac71 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -6,6 +6,9 @@ on:
pull_request:
branches: [ "master" ]
+permissions:
+ contents: read
+
jobs:
build:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..d7f635b
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,80 @@
+# Manual workflow: publish to NuGet and create a GitHub release with source zip.
+# Run from Actions tab → "Publish and Release" → "Run workflow".
+# Required secrets: NUGET_API_KEY (https://www.nuget.org/account/apikeys)
+
+name: Publish and Release
+
+on:
+ workflow_dispatch:
+ inputs:
+ version:
+ description: 'Release version (e.g. 8.0.0.x). Tag will be v{version}.'
+ required: true
+ type: string
+ nuget_publish:
+ description: 'Publish package to NuGet.org'
+ required: false
+ default: true
+ type: boolean
+
+env:
+ NUGET_SOURCE: 'https://api.nuget.org/v3/index.json'
+
+jobs:
+ publish-and-release:
+ runs-on: windows-latest
+ permissions:
+ contents: write # create tag and release, upload assets
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v6
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v5
+ with:
+ dotnet-version: '10.0.x'
+
+ - name: Restore dependencies
+ run: dotnet restore
+
+ - name: Build
+ run: dotnet build --no-restore -c Release
+
+ - name: Pack (ensure .nupkg output)
+ run: dotnet pack N.EntityFrameworkCore.Extensions/N.EntityFrameworkCore.Extensions.csproj --no-build -c Release -o out
+ id: pack
+
+ - name: Publish to NuGet
+ if: ${{ inputs.nuget_publish }}
+ run: dotnet nuget push .\out\*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source ${{ env.NUGET_SOURCE }} --skip-duplicate
+ env:
+ NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
+
+ - name: Create source zip
+ run: |
+ $tag = "v${{ inputs.version }}"
+ git archive --format=zip --output=source-$tag.zip HEAD
+ echo "SOURCE_ZIP=source-$tag.zip" >> $env:GITHUB_ENV
+ echo "ARCHIVE_NAME=source-$tag.zip" >> $env:GITHUB_ENV
+
+ - name: Get .nupkg path
+ id: nupkg
+ run: |
+ $nupkg = Get-ChildItem -Path out -Filter "*.nupkg" | Select-Object -First 1
+ echo "path=$($nupkg.FullName)" >> $env:GITHUB_OUTPUT
+ echo "name=$($nupkg.Name)" >> $env:GITHUB_OUTPUT
+
+ - name: Create GitHub Release
+ uses: softprops/action-gh-release@v2
+ with:
+ tag_name: v${{ inputs.version }}
+ name: Release v${{ inputs.version }}
+ generate_release_notes: true
+ files: |
+ ${{ env.ARCHIVE_NAME }}
+ ${{ steps.nupkg.outputs.path }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/N.EntityFrameworkCore.Extensions.Test/DbContextExtensions/BulkInsert.cs b/N.EntityFrameworkCore.Extensions.Test/DbContextExtensions/BulkInsert.cs
index ae7e5f0..81b2b01 100644
--- a/N.EntityFrameworkCore.Extensions.Test/DbContextExtensions/BulkInsert.cs
+++ b/N.EntityFrameworkCore.Extensions.Test/DbContextExtensions/BulkInsert.cs
@@ -378,12 +378,15 @@ public void With_Trigger()
{
products.Add(new ProductWithTrigger { Id = i.ToString(), Price = 1.57M, StatusString="InStock" });
}
- int rowsInserted = dbContext.BulkInsert(products, options => {
+
+ //The return int from BulkInsert() will be off when using triggers
+ dbContext.BulkInsert(products, options => {
options.AutoMapOutput = false;
options.BulkCopyOptions = SqlBulkCopyOptions.FireTriggers;
});
+ var rowsInserted = dbContext.ProductsWithTrigger.Count();
- Assert.IsTrue(rowsInserted == products.Count, "The number of rows inserted must match the count of products");
+ Assert.IsTrue(rowsInserted == products.Count , $"The number of rows inserted must match the count of products ({rowsInserted}!={products.Count})");
}
[TestMethod]
public void With_ValueGenerated_Default()
diff --git a/N.EntityFrameworkCore.Extensions.Test/DbContextExtensions/BulkSaveChanges.cs b/N.EntityFrameworkCore.Extensions.Test/DbContextExtensions/BulkSaveChanges.cs
index 19562ea..d2f9fbc 100644
--- a/N.EntityFrameworkCore.Extensions.Test/DbContextExtensions/BulkSaveChanges.cs
+++ b/N.EntityFrameworkCore.Extensions.Test/DbContextExtensions/BulkSaveChanges.cs
@@ -61,6 +61,7 @@ public void With_Add_Changes()
int rowsAffected = dbContext.BulkSaveChanges();
int newTotalCount = dbContext.Orders.Where(o => o.Price == 10.57M).Count();
+ Assert.IsTrue(ordersToAdd.Where(o => o.Id <= 0).Count() == 0, "Primary key should have been updated for all entities");
Assert.IsTrue(rowsAffected == ordersToAdd.Count, "The number of rows affected must equal the sum of entities added, deleted and updated");
Assert.IsTrue(oldTotalCount + ordersToAdd.Count == newTotalCount, "The number of orders to add did not match what was expected.");
}
diff --git a/N.EntityFrameworkCore.Extensions.Test/DbContextExtensions/BulkSaveChangesAsync.cs b/N.EntityFrameworkCore.Extensions.Test/DbContextExtensions/BulkSaveChangesAsync.cs
index 9bb39b9..ceaea35 100644
--- a/N.EntityFrameworkCore.Extensions.Test/DbContextExtensions/BulkSaveChangesAsync.cs
+++ b/N.EntityFrameworkCore.Extensions.Test/DbContextExtensions/BulkSaveChangesAsync.cs
@@ -63,6 +63,7 @@ public async Task With_Add_Changes()
int rowsAffected = await dbContext.BulkSaveChangesAsync();
int newTotalCount = dbContext.Orders.Where(o => o.Price == 10.57M).Count();
+ Assert.IsTrue(ordersToAdd.Where(o => o.Id <= 0).Count() == 0, "Primary key should have been updated for all entities");
Assert.IsTrue(rowsAffected == ordersToAdd.Count, "The number of rows affected must equal the sum of entities added, deleted and updated");
Assert.IsTrue(oldTotalCount + ordersToAdd.Count == newTotalCount, "The number of orders to add did not match what was expected.");
}
diff --git a/N.EntityFrameworkCore.Extensions.Test/N.EntityFrameworkCore.Extensions.Test.csproj b/N.EntityFrameworkCore.Extensions.Test/N.EntityFrameworkCore.Extensions.Test.csproj
index 8e1c263..705f519 100644
--- a/N.EntityFrameworkCore.Extensions.Test/N.EntityFrameworkCore.Extensions.Test.csproj
+++ b/N.EntityFrameworkCore.Extensions.Test/N.EntityFrameworkCore.Extensions.Test.csproj
@@ -17,9 +17,9 @@
-
-
-
+
+
+
diff --git a/N.EntityFrameworkCore.Extensions/Data/DbContextExtensions.cs b/N.EntityFrameworkCore.Extensions/Data/DbContextExtensions.cs
index fccd9fb..a68ee1e 100644
--- a/N.EntityFrameworkCore.Extensions/Data/DbContextExtensions.cs
+++ b/N.EntityFrameworkCore.Extensions/Data/DbContextExtensions.cs
@@ -5,6 +5,7 @@
using System.IO;
using System.Linq;
using System.Linq.Expressions;
+using System.Runtime.CompilerServices;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
@@ -247,8 +248,12 @@ internal static void SetStoreGeneratedValues(this DbContext context, T entity
{
foreach (var property in properties)
{
- if (!property.IsPrimaryKey() ||
- (property.IsPrimaryKey() && updateEntry.EntityState == EntityState.Detached))
+ if((updateEntry.EntityState == EntityState.Added &&
+ (property.ValueGenerated == ValueGenerated.OnAdd|| property.ValueGenerated == ValueGenerated.OnAddOrUpdate)) ||
+ (updateEntry.EntityState == EntityState.Modified &&
+ (property.ValueGenerated == ValueGenerated.OnUpdate || property.ValueGenerated == ValueGenerated.OnAddOrUpdate)) ||
+ updateEntry.EntityState == EntityState.Detached
+ )
{
try
{
diff --git a/N.EntityFrameworkCore.Extensions/N.EntityFrameworkCore.Extensions.csproj b/N.EntityFrameworkCore.Extensions/N.EntityFrameworkCore.Extensions.csproj
index 54607a8..48f1c1f 100644
--- a/N.EntityFrameworkCore.Extensions/N.EntityFrameworkCore.Extensions.csproj
+++ b/N.EntityFrameworkCore.Extensions/N.EntityFrameworkCore.Extensions.csproj
@@ -2,11 +2,11 @@
net8.0
- 8.0.0.12
+ 8.0.0.13
true
https://github.com/NorthernLight1/N.EntityFrameworkCore.Extensions/
Northern25
- Copyright © 2024
+ Copyright © 2026
N.EntityFrameworkCore.Extensions extends your DbContext in EF Core with high-performance bulk operations: BulkDelete, BulkInsert, BulkMerge, BulkSync, BulkUpdate, Fetch, DeleteFromQuery, InsertFromQuery, UpdateFromQuery.