CoreOne.ModelPatch.Abstract 1.0.1

dotnet add package CoreOne.ModelPatch.Abstract --version 1.0.1
                    
NuGet\Install-Package CoreOne.ModelPatch.Abstract -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CoreOne.ModelPatch.Abstract" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CoreOne.ModelPatch.Abstract" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="CoreOne.ModelPatch.Abstract" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CoreOne.ModelPatch.Abstract --version 1.0.1
                    
#r "nuget: CoreOne.ModelPatch.Abstract, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CoreOne.ModelPatch.Abstract@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CoreOne.ModelPatch.Abstract&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=CoreOne.ModelPatch.Abstract&version=1.0.1
                    
Install as a Cake Tool

CoreOne.ModelPatch.Abstract

The abstractions package for CoreOne.ModelPatch — providing the interfaces, models, and core types needed to build and extend partial update (PATCH) pipelines for EF Core entities.

Install this package when you want to reference the CoreOne.ModelPatch contracts without taking a dependency on the full implementation — for example, in a shared domain or plugin library.

📦 Installation

dotnet add package CoreOne.ModelPatch.Abstract

Requirements: net9.0 or net10.0


What's Included

Delta Types

Delta and Delta<T> are case-insensitive dictionaries that hold only the properties you explicitly include in a partial update. The generic version gives you compile-time type safety.

// Untyped — useful for dynamic scenarios
var delta = new Delta();
delta["Name"] = "Alice";
delta["Email"] = "alice@example.com";

// Typed — tied to a specific entity
var typed = new Delta<User>();
typed["Name"] = "Alice";

DeltaCollection<T> is a list of Delta<T> for batch operations.


IDataModelService<TContext>

The primary service interface your application uses to apply patches. Inject this to avoid a hard dependency on the implementation assembly.

public class UserService(IDataModelService<AppDbContext> patchService)
{
    public Task<PatchResult> PatchUser(Delta<User> delta, CancellationToken ct)
        => patchService.Patch(delta, ct);
}

Methods:

Method Description
Patch<T>(Delta<T>, ct) Patch a single entity
Patch<T>(DeltaCollection<T>, ct) Patch a batch of entities
PatchCollection(IEnumerable<object?>, ct) Patch a mixed collection of untyped objects

Plugin Interfaces

Implement these to inject custom logic into the patch pipeline.

Interface When it runs Typical uses
IPrePatchPlugin Before the delta is applied Validation, enrichment, tenant injection
IPostPatchPlugin After the delta is applied Model-state validation, auditing

Both interfaces expose an Order property (higher = runs first). Implement them and register with DI:

// Custom pre-patch plugin
public class AuditPlugin : IPrePatchPlugin
{
    public int Order => 500;

    public ValueTask<IResult> Execute(ModelProcessContext context, CancellationToken ct)
    {
        context.Delta["UpdatedAt"] = DateTime.UtcNow;
        return ValueTask.FromResult(Result.Ok);
    }
}

// Register
services.TryAddEnumerable(ServiceDescriptor.Scoped<IPrePatchPlugin, AuditPlugin>());

IKeyGenerator

Implement this to provide custom primary key generation for your entities.

// Use the strongly-typed generic form
public class SequentialIdGenerator : IKeyGenerator<int>
{
    private static int _counter = 0;

    public int Create() => Interlocked.Increment(ref _counter);

    public KeyModel CreateKey() => new KeyModel(Create());
}

Register per entity type in ModelOptions:

services.Configure<ModelOptions>(o =>
    o.KeyGenerators[typeof(MyEntity)] = new SequentialIdGenerator());

ModelOptions

Controls patching behavior. Configure via services.Configure<ModelOptions>(...) or pass directly.

Property Type Default Description
StrictPropertyMatching bool false Fail when delta contains a field not on the entity
ValidateConcurrencyTokens bool true Check [Timestamp]/[ConcurrencyCheck] tokens on update
RequireConcurrencyTokenForUpdates bool false Require a token to be present in update deltas
NameResolver Func<Metadata, string>? null Map entity properties to delta key names (e.g., JSON attribute names)
IgnoreFields DataHashSet<Type, string> empty Properties to skip during patching, per entity type
KeyGenerators Data<Type, IKeyGenerator> empty Per-type primary key generators
ExcludePlugins HashSet<Type> empty Plugin types to skip for this context

PatchResult

Returned by every patch call. Inspect it to determine what was created, updated, or left unchanged.

var result = await patchService.Patch(delta, ct);

if (result.ResultType == ResultType.Success)
{
    Console.WriteLine($"Created: {result.Created}");
    Console.WriteLine($"Updated: {result.Updated}");

    // Retrieve a specific patched entity
    var user = result.Get<User>();
}

PatchRestrictAttribute

Apply to entity properties to control whether they may be included in a patch delta.

public class User
{
    public Guid Id { get; set; }
    public string Name { get; set; }

    // Cannot be changed via patch — silently dropped from delta
    [PatchRestrict(PatchRestrictionType.DenyUpdateSilently)]
    public DateTime CreatedAt { get; set; }

    // If present in delta, the entire patch fails with a 400-like error
    [PatchRestrict(PatchRestrictionType.DenyUpdateBadRequest)]
    public string Role { get; set; }
}
Value Behavior
DenyUpdateSilently Property is removed from the delta; patch continues normally
DenyUpdateBadRequest Patch fails if this property appears in the delta

ModelProcessContext

Passed to every plugin. Gives access to the current delta, entity type, entity instance, and CRUD state.

public ValueTask<IResult> Execute(ModelProcessContext context, CancellationToken ct)
{
    // The partial update data
    var delta = context.Delta;

    // The CLR type being patched
    var entityType = context.Type;

    // The tracked EF Core entity (may be null before it's resolved)
    var entity = context.Model;

    // Whether this is a Create or Update
    var state = context.State; // CrudType.Created | CrudType.Updated
    return ValueTask.FromResult(Result.Ok);
}

Package Description
CoreOne.ModelPatch Full implementation — register with services.AddModelPatch()
CoreOne.ModelPatch.Tenants Optional multi-tenancy plugin for tenant key injection and validation

License

MIT — see LICENSE on GitHub.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on CoreOne.ModelPatch.Abstract:

Package Downloads
CoreOne.ModelPatch

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 120 5/4/2026
1.0.0 121 4/24/2026