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
48 changes: 33 additions & 15 deletions FORK.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ and packaging.

1. **Never edit upstream source files.** Everything the fork needs lives in files upstream does not
have. This is what keeps upstream merges conflict-free. The one exception is
`src/Z.EntityFramework.Plus.sln`, which gains the fork's three projects — 20 additive lines: the
`Project` entries, `Debug|Any CPU` / `Release|Any CPU` mappings, and nesting of the two test projects
under the `test` folder. If a merge conflicts there, take upstream's file and re-add the three
projects from the IDE. `dotnet sln add` also works, but it invents `x64` and `x86` solution platforms
`src/Z.EntityFramework.Plus.sln`, which gains the fork's projects — about 30 additive lines: `Project`
entries and `Debug|Any CPU` / `Release|Any CPU` mappings for the three csproj, `.shproj` entries for the
two shared projects, nesting under the `shared` and `test` folders, and the `SharedMSBuildProjectFiles`
lines that tie each `.projitems` to the projects importing it. If a merge conflicts there, take
upstream's file and re-add the projects from the IDE. `dotnet sln add` also works, but it invents `x64` and `x86` solution platforms
and writes mappings for *every* project in the solution (200 lines); strip those before committing —
upstream's solution is `Any CPU` only.
2. **`master` mirrors upstream exactly.** Never commit to it; only `git pull upstream master`.
Expand Down Expand Up @@ -55,7 +56,7 @@ reimplementation of Query Hook or bulk operations.
## The shim

Upstream's EF Core shared code reaches the two paid assemblies in two very different ways, and the
shim (`src/Z.EntityFramework.Plus.EFCore10x.NET10/Shim/`) answers both. Everything is `internal` —
shim (`src/shared/Z.EF.Plus.MIT.Shared/Shim/`) answers both. Everything is `internal` —
except `EntityFrameworkManager`, public because its `ContextFactory` is a hook consumers set (see the
Batch section) — compiled into the Plus assembly, in the namespaces upstream code imports — `Shim/Extensions/` holds
`Z.EntityFramework.Extensions`, `Shim/EvalManager.cs` holds `Z.Expressions`, and
Expand Down Expand Up @@ -225,13 +226,15 @@ reflection over public API and cached per (entity type, member type, overload).
build.yml # build + test + pack on every push/PR
publish.yml # tag mit/<version> → nuget.org
src/
Z.EntityFramework.Plus.sln # upstream's solution + the three fork projects (see ground rule 1)
EntityFrameworkPlus.EFCore.MIT.slnf # solution filter: only the fork's projects — open this one
Z.EntityFramework.Plus.EFCore10x.NET10/ # the library — mirrors EFCore9x.NET8
Z.EntityFramework.Plus.sln # upstream's solution + the fork's projects (see ground rule 1)
EntityFrameworkPlus.EFCore.MIT.slnf # solution filter: only the fork's buildable projects — open this one
Z.EntityFramework.Plus.EFCore10x.NET10/ # the library for EF Core 10 — mirrors EFCore9x.NET8; the csproj alone
Z.EntityFramework.Plus.EFCore10x.NET10.csproj
shared/Z.EF.Plus.MIT.Shared/ # the fork's own code, imported by every EFCore1Nx csproj like upstream's feature folders
Z.EF.Plus.MIT.Shared.projitems # the file list; .shproj beside it is for the IDE
Shim/
Extensions/ # namespace Z.EntityFramework.Extensions
EntityFrameworkManager.cs
EntityFrameworkManager.cs # + ContextFactory, the InMemory hook (public)
PublicMethods.cs
PublicExtensions.cs
QueryCommandExtensions.cs # the compile step
Expand All @@ -245,10 +248,11 @@ src/
InMemoryContext.cs # the second context both fallbacks save through: ContextFactory, or the context's type from its options
test/
Z.Test.EntityFramework.Plus.EFCore100/ # upstream's shared test suite against this build — mirrors EFCore90
EntityFrameworkPlus.EFCore.MIT.Smoke/ # fork-owned xunit + Shouldly smoke tests, one folder per feature
EntityFrameworkPlus.EFCore.MIT.Smoke.Shared/ # fork-owned xunit + Shouldly smoke tests, one folder per feature; .projitems + .shproj
ShouldExtensions.cs # ShouldBeInOrder: sequence assertions as "these elements, in this order"
QueryFuture/ # round trips on SQL Server + InMemory: QueryFutureTests.SqlServer / .InMemory and their fixtures
Batch/ # Batch Update / Delete on InMemory + SQLite: one test class per extension class, one part per method
EntityFrameworkPlus.EFCore.MIT.Smoke.EFCore100/ # the smoke tests against the EF Core 10 build: target framework, package pins, project reference
FORK.md # this file
README.md # the fork's readme; packed as the nuget.org readme too
```
Expand All @@ -260,9 +264,9 @@ The library csproj mirrors `Z.EntityFramework.Plus.EFCore9x.NET8.csproj` with th
| `TargetFramework` | `net8.0` | `net10.0` |
| `AssemblyName` / `RootNamespace` | `Z.EntityFramework.Plus.EFCore` | `EntityFrameworkPlus.EFCore.MIT` / `Z.EntityFramework.Plus` (no `.resx` anywhere, so the change is safe) |
| `DefineConstants` | `… EFCORE_8X EFCORE_9X` | same + `EFCORE_10X` (upstream already guards with it) |
| `<Import>` list | 15 projitems | 12 — without `BatchDelete` and `BatchUpdate` (replaced by `Batch/`) and `QueryHook` |
| `<Import>` list | 15 projitems | 13 — upstream's without `BatchDelete` and `BatchUpdate` (replaced by the fork's `Batch/`) and `QueryHook`, plus `Z.EF.Plus.MIT.Shared` |
| `PackageReference` | EF Relational 9.0.0, `Z.EntityFramework.Extensions.EFCore`, `Z.Expressions.Eval` | `Microsoft.EntityFrameworkCore.Relational` 10.0.0 only |
| Fork sources | — | `Shim\**\*.cs` and `Batch\**\*.cs`, via the SDK's default globbing |
| Fork sources | — | through the `Z.EF.Plus.MIT.Shared` import; the project folder holds only the csproj |
| `NoWarn` | — | `CS1591` (upstream XML docs are incomplete), `EF1001` (upstream reflects EF internals by design) |
| `SignAssembly` | `False` | `False` (no key needed) |

Expand All @@ -286,6 +290,13 @@ copies have drifted); and a fork-owned `DeleteFromQuery` → `ExecuteDelete()` h
IncludeOptimized-with-Future repro test keeps compiling. No `App.config`: it is EF6-era configuration and
the shared tests hard-code their connection string.

The smoke tests follow the same split: the sources are `EntityFrameworkPlus.EFCore.MIT.Smoke.Shared`, a
`.projitems` like upstream's, and `EntityFrameworkPlus.EFCore.MIT.Smoke.EFCore100` is a csproj holding only
the target framework, the package pins and the project reference. An EF Core 11 target adds
`…Smoke.EFCore110` and nothing else. The SQL Server database name `EFPlusMitSmoke` is shared by every
version, so two versions must not run against one server at once; suffix it per version when the second
arrives.

## Build, verify, publish

Prerequisites: .NET SDK 10.0.x; a local trusted SQL Server (`localhost`). Both test projects create
Expand Down Expand Up @@ -412,9 +423,12 @@ ours and prefer theirs.
- **`AssemblyName` renamed** to `EntityFrameworkPlus.EFCore.MIT`: provenance visible in `bin/`, and
no two DLLs with the same name if both packages ever meet. Namespaces stay `Z.EntityFramework.Plus`
because upstream code is untouched, so consumer code changes only its `PackageReference`.
- **Shim lives in the library project** (`Shim/`, sub-folders mirror namespaces); promote to a shared
projitems only if a second EF Core target is ever added.
- **Upstream's solution is the entry point**; the fork's three projects are added to it (ground rule 1).
- **Fork-owned code is a shared project**, `src/shared/Z.EF.Plus.MIT.Shared` (`Shim/` and `Batch/`),
imported by each versioned csproj exactly like upstream's feature folders, so an EF Core 11 project is a
csproj plus `#if EFCORE_11X` branches wherever EF's internals moved. It started inside the 10x project
and was promoted once EF Core 11 was two months out: a rename-only change then, rather than a rename
buried inside the port.
- **Upstream's solution is the entry point**; the fork's projects are added to it (ground rule 1).
- **Tests = upstream's own suite + a fork-owned smoke test.** Upstream's suite proves the features
still behave; the smoke test proves the one thing upstream's suite cannot (single round trip, and
scalar futures under buffering).
Expand Down Expand Up @@ -465,3 +479,7 @@ Open:
the shared-context version flushing the unit of work's pending changes: `EntityFrameworkManager.ContextFactory`
(EF Extensions' hook, now public in the shim) or the context's own type from its options;
`TrackedInstances` removed. Smoke 43/43, upstream 270/270.
- 2026-09-25 — `mit/10.105.8.1-preview.2` published from `master-MIT` after PR #3 (batch) and PR #4 (both
`ContextFactory` failure paths covered). Fork-owned code promoted to shared projects,
`Z.EF.Plus.MIT.Shared` for the library and `EntityFrameworkPlus.EFCore.MIT.Smoke.Shared` for the tests,
with one smoke csproj per EF Core version (`…Smoke.EFCore100`). Package content unchanged.
2 changes: 1 addition & 1 deletion src/EntityFrameworkPlus.EFCore.MIT.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"projects": [
"Z.EntityFramework.Plus.EFCore10x.NET10\\Z.EntityFramework.Plus.EFCore10x.NET10.csproj",
"test\\Z.Test.EntityFramework.Plus.EFCore100\\Z.Test.EntityFramework.Plus.EFCore100.csproj",
"test\\EntityFrameworkPlus.EFCore.MIT.Smoke\\EntityFrameworkPlus.EFCore.MIT.Smoke.csproj"
"test\\EntityFrameworkPlus.EFCore.MIT.Smoke.EFCore100\\EntityFrameworkPlus.EFCore.MIT.Smoke.EFCore100.csproj"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
<Import Project="..\shared\Z.EF.Plus.SetDynamic.Shared\Z.EF.Plus.SetDynamic.Shared.projitems" Label="Shared" />
<Import Project="..\shared\Z.EF.Plus.SetIdentity.Shared\Z.EF.Plus.SetIdentity.Shared.projitems" Label="Shared" />

<!-- Shim\**\*.cs (the replacement for the paid-assembly surface) and Batch\**\*.cs (Batch Update/Delete on ExecuteUpdate/ExecuteDelete) are picked up by the SDK's default globbing. -->
<!-- The fork's own code: Shim\ (the replacement for the paid-assembly surface) and Batch\ (Batch Update/Delete on ExecuteUpdate/ExecuteDelete). -->
<Import Project="..\shared\Z.EF.Plus.MIT.Shared\Z.EF.Plus.MIT.Shared.projitems" Label="Shared" />

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.0" />
Expand Down
12 changes: 11 additions & 1 deletion src/Z.EntityFramework.Plus.sln
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Z.EntityFramework.Plus.EFCo
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Z.Test.EntityFramework.Plus.EFCore100", "test\Z.Test.EntityFramework.Plus.EFCore100\Z.Test.EntityFramework.Plus.EFCore100.csproj", "{E05FECB0-4B8F-46BD-B9BE-DA07FAABEF87}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkPlus.EFCore.MIT.Smoke", "test\EntityFrameworkPlus.EFCore.MIT.Smoke\EntityFrameworkPlus.EFCore.MIT.Smoke.csproj", "{958551B0-2B7C-4FB4-8E84-EE63754B555E}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkPlus.EFCore.MIT.Smoke.EFCore100", "test\EntityFrameworkPlus.EFCore.MIT.Smoke.EFCore100\EntityFrameworkPlus.EFCore.MIT.Smoke.EFCore100.csproj", "{958551B0-2B7C-4FB4-8E84-EE63754B555E}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Z.EF.Plus.MIT.Shared", "shared\Z.EF.Plus.MIT.Shared\Z.EF.Plus.MIT.Shared.shproj", "{831BE291-5EFF-4665-B364-6D7B289F4E4A}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "EntityFrameworkPlus.EFCore.MIT.Smoke.Shared", "test\EntityFrameworkPlus.EFCore.MIT.Smoke.Shared\EntityFrameworkPlus.EFCore.MIT.Smoke.Shared.shproj", "{7F966A0F-4B95-4740-A28E-61B344EF6C90}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -226,11 +230,17 @@ Global
{3DC354A7-ED8E-8A7E-7D56-CCEBD075B24B} = {14D8985E-0AA8-444A-A32E-D766ABA114D6}
{A287860E-A64B-AA50-F418-D011CD4CA8B0} = {14D8985E-0AA8-444A-A32E-D766ABA114D6}
{DB1D9715-C703-4F6D-BF3B-16F0228F3A60} = {14D8985E-0AA8-444A-A32E-D766ABA114D6}
{831BE291-5EFF-4665-B364-6D7B289F4E4A} = {45D50C58-9B18-475A-9839-D6754E87352B}
{7F966A0F-4B95-4740-A28E-61B344EF6C90} = {14D8985E-0AA8-444A-A32E-D766ABA114D6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AEE441E3-DEE9-48F2-9212-1F3A573007AE}
EndGlobalSection
GlobalSection(SharedMSBuildProjectFiles) = preSolution
shared\Z.EF.Plus.MIT.Shared\Z.EF.Plus.MIT.Shared.projitems*{4edee6e6-27a0-4793-9650-865445b367d5}*SharedItemsImports = 5
shared\Z.EF.Plus.MIT.Shared\Z.EF.Plus.MIT.Shared.projitems*{831be291-5eff-4665-b364-6d7b289f4e4a}*SharedItemsImports = 13
test\EntityFrameworkPlus.EFCore.MIT.Smoke.Shared\EntityFrameworkPlus.EFCore.MIT.Smoke.Shared.projitems*{958551b0-2b7c-4fb4-8e84-ee63754b555e}*SharedItemsImports = 5
test\EntityFrameworkPlus.EFCore.MIT.Smoke.Shared\EntityFrameworkPlus.EFCore.MIT.Smoke.Shared.projitems*{7f966a0f-4b95-4740-a28e-61b344ef6c90}*SharedItemsImports = 13
test\Z.Test.EntityFramework.Plus.EF6.Shared\Z.Test.EntityFramework.Plus.EF6.Shared.projitems*{063fa382-dfda-4bcb-bbb6-aac04d0ed88e}*SharedItemsImports = 4
test\Z.Test.EntityFramework.Plus.Test.Shared\Z.Test.EntityFramework.Plus.Test.Shared.projitems*{063fa382-dfda-4bcb-bbb6-aac04d0ed88e}*SharedItemsImports = 4
shared\Z.EF.Plus.Audit.Shared\Z.EF.Plus.Audit.Shared.projitems*{1b28efb7-e679-4275-aca9-da7cd589a56a}*SharedItemsImports = 4
Expand Down
37 changes: 37 additions & 0 deletions src/shared/Z.EF.Plus.MIT.Shared/Z.EF.Plus.MIT.Shared.projitems
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="SharedProjectFile_SccProperties">
<SharedProjectFile_ProjectGuid>{44d18132-b8db-44d5-aa64-551c7d38f1ba}</SharedProjectFile_ProjectGuid>
<SharedProjectFile_SccProjectName></SharedProjectFile_SccProjectName>
<SharedProjectFile_SccAuxPath></SharedProjectFile_SccAuxPath>
<SharedProjectFile_SccLocalPath></SharedProjectFile_SccLocalPath>
<SharedProjectFile_SccProvider></SharedProjectFile_SccProvider>
</PropertyGroup>
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>831be291-5eff-4665-b364-6d7b289f4e4a</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>Z.EF.Plus.MIT.Shared</Import_RootNamespace>
</PropertyGroup>
<!--
The fork's own code, imported by every EFCore1Nx project the way upstream's feature folders are:
Shim\ stands in for the Z.EntityFramework.Extensions / Z.Expressions.Eval surface upstream calls,
Batch\ is Batch Update / Delete on ExecuteUpdate / ExecuteDelete. Version drift goes behind
EFCORE_xX symbols here, as in upstream's shared code.
-->
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Batch\BatchDeleteExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Batch\BatchDeleteExtensions.InMemory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Batch\BatchUpdateExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Batch\BatchUpdateExtensions.InMemory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Batch\InMemoryContext.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Shim\EntityTypeInfoExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Shim\EvalManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Shim\Extensions\EntityFrameworkManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Shim\Extensions\PublicExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Shim\Extensions\PublicMethods.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Shim\Extensions\QueryCommandExtensions.cs" />
</ItemGroup>
</Project>
21 changes: 21 additions & 0 deletions src/shared/Z.EF.Plus.MIT.Shared/Z.EF.Plus.MIT.Shared.shproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>831be291-5eff-4665-b364-6d7b289f4e4a</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<SccProjectName>
</SccProjectName>
<SccProvider>
</SccProvider>
<SccAuxPath>
</SccAuxPath>
<SccLocalPath>
</SccLocalPath>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="Z.EF.Plus.MIT.Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<!--
Smoke tests for the MIT build: Query Future still combines queries into one round trip, with entity
graphs, scalar futures, parameter renaming, global-filter runtime parameters and a buffering (retrying)
execution strategy, on SQL Server and on the InMemory provider;
Batch Update / Delete behave the same on SQLite (ExecuteUpdate / ExecuteDelete) and on InMemory (the load-and-save fallback).
The smoke tests against the EF Core 10 build. The tests live in EntityFrameworkPlus.EFCore.MIT.Smoke.Shared;
this project holds only the target framework, the package pins and the project reference, one such project
per EF Core version.
-->

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>EntityFrameworkPlus.EFCore.MIT.Smoke</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<IsPackable>false</IsPackable>
Expand All @@ -34,4 +34,6 @@
<ProjectReference Include="..\..\Z.EntityFramework.Plus.EFCore10x.NET10\Z.EntityFramework.Plus.EFCore10x.NET10.csproj" />
</ItemGroup>

<Import Project="..\EntityFrameworkPlus.EFCore.MIT.Smoke.Shared\EntityFrameworkPlus.EFCore.MIT.Smoke.Shared.projitems" Label="Shared" />

</Project>
Loading
Loading