TinyHelpers.EntityFrameworkCore 3.0.76

There is a newer version of this package available.
See the version list below for details.
dotnet add package TinyHelpers.EntityFrameworkCore --version 3.0.76
                    
NuGet\Install-Package TinyHelpers.EntityFrameworkCore -Version 3.0.76
                    
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="TinyHelpers.EntityFrameworkCore" Version="3.0.76" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="TinyHelpers.EntityFrameworkCore" Version="3.0.76" />
                    
Directory.Packages.props
<PackageReference Include="TinyHelpers.EntityFrameworkCore" />
                    
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 TinyHelpers.EntityFrameworkCore --version 3.0.76
                    
#r "nuget: TinyHelpers.EntityFrameworkCore, 3.0.76"
                    
#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 TinyHelpers.EntityFrameworkCore@3.0.76
                    
#: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=TinyHelpers.EntityFrameworkCore&version=3.0.76
                    
Install as a Cake Addin
#tool nuget:?package=TinyHelpers.EntityFrameworkCore&version=3.0.76
                    
Install as a Cake Tool

Tiny Helpers for Entity Framework Core

Lint Code Base CodeQL NuGet NuGet License: MIT

TinyHelpers.EntityFrameworkCore is a small collection of practical helpers for Entity Framework Core applications: value converters, value comparers, global query filters, transaction helpers, and vector-column mapping.

The package is designed to reduce repetitive configuration and keep the intent of your EF Core model close to the entity type that uses it.

Compatibility

The package targets:

  • .NET 8
  • .NET 9
  • .NET 10

Some features are framework-specific:

  • Named query filters are available only on .NET 10+
  • The package focuses on EF Core model configuration, conversions, and transaction helpers

Installation

Install the package from NuGet:

dotnet add package TinyHelpers.EntityFrameworkCore

Or search for TinyHelpers.EntityFrameworkCore in the Visual Studio Package Manager.

Contents

Converters and comparers

This area contains helpers for storing common CLR shapes in a single database column while keeping EF Core change tracking aligned with the persisted representation.

JsonStringConverter<T>

Converts a CLR object graph to and from a JSON string.

Use it when you want to store a complex type in a text column without manually handling serialization in every entity configuration.

JsonStringComparer<T>

Compares values by their JSON representation.

Use it together with JsonStringConverter<T> so EF Core detects changes based on serialized content instead of object reference identity.

StringArrayConverter

Converts a sequence of strings to a single delimiter-separated value.

Use it when a small string collection should be stored in one column and you do not need a separate relational table.

StringArrayComparer

Compares string sequences by content and order.

Use it together with StringArrayConverter so EF Core treats two collections as equal when they contain the same values in the same order.

StringEmptyToNullConverter

Normalizes blank strings to null before persistence.

Use it when an empty or whitespace-only value should be treated as the absence of data.

StringEmptyToNullTrimConverter

Normalizes blank strings to null and trims meaningful values before persistence.

Use it when user input should not preserve incidental leading or trailing whitespace.

Property builder helpers

PropertyBuilderExtensions

These helpers keep the most common EF Core configuration patterns in one place.

Method What it does When to use it
HasJsonConversion<T>(this PropertyBuilder<T?>, JsonSerializerOptions?, bool useUtcDate, bool serializeEnumAsString) Stores a property as JSON and wires up matching change tracking. When a complex object should be persisted in a single text column.
HasArrayConversion(this PropertyBuilder<IEnumerable<string>>) Stores a string sequence as a single delimited column. When the property is exposed as IEnumerable<string>.
HasArrayConversion(this PropertyBuilder<string[]>) Stores a string array as a single delimited column. When the property is exposed as string[].
IsVector(this PropertyBuilder, int size = 1536) Maps the property to a vector column type. When the database supports vector search or embeddings.
IsVector<T>(this PropertyBuilder<T>, int size = 1536) Strongly typed version of IsVector. When the property is strongly typed and you want fluent chaining.

Example

using Microsoft.EntityFrameworkCore;
using TinyHelpers.EntityFrameworkCore.Extensions;

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>(builder =>
    {
        builder.Property(x => x.Metadata).HasJsonConversion();
        builder.Property(x => x.Tags).HasArrayConversion(",");
        builder.Property(x => x.Embedding).IsVector(1536);
    });
}

Query filters

ModelBuilderExtensions

These helpers make it easier to apply the same global filter to multiple entity types.

Method What it does When to use it
ApplyQueryFilter<TEntity>(Expression<Func<TEntity, bool>>) Applies the same filter to all entity types assignable to TEntity. When several entities share a common base type or interface.
ApplyQueryFilter<TType>(string propertyName, TType value) Applies a filter to all entity types that expose a property with the given name and type. When the same property exists across multiple entity types.
ApplyQueryFilter<TEntity>(string filterName, Expression<Func<TEntity, bool>>) .NET 10+ named filter overload. When you want to selectively disable one filter later.
ApplyQueryFilter<TType>(string filterName, string propertyName, TType value) .NET 10+ named filter overload for a property match. When you need named filters for shared properties.
GetEntityTypes<TType>() Returns the CLR entity types assignable to TType. When you need the model types behind a base type or interface.
GetEntityTypes(Type baseType) Returns the CLR entity types assignable to a runtime type. When the target type is only known at runtime.

Example

using Microsoft.EntityFrameworkCore;
using TinyHelpers.EntityFrameworkCore.Extensions;

public abstract class DeletableEntity
{
    public bool IsDeleted { get; set; }
}

public interface ISoftDeletable
{
    bool IsDeleted { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyQueryFilter<DeletableEntity>(e => !e.IsDeleted);
    modelBuilder.ApplyQueryFilter<ISoftDeletable>(e => !e.IsDeleted);
}

.NET 10 named filters

Starting with .NET 10, named filters let you attach a name to each query filter and disable only the ones you need:

modelBuilder.ApplyQueryFilter<ISoftDeletable>("SoftDelete", e => !e.IsDeleted);
modelBuilder.ApplyQueryFilter<ITenantEntity>("TenantFilter", e => e.TenantId == currentTenantId);

Later, you can disable just one filter:

var items = await context.Set<Order>().IgnoreQueryFilters(["SoftDelete"]).ToListAsync();

Transaction helpers

DbContextExtensions

These helpers wrap EF Core execution strategies and transactions so the retry behavior stays consistent.

Method What it does When to use it
ExecuteTransactionAsync(Func<CancellationToken, Task>) Runs work inside a transaction and commits when the action completes. When you do not need the transaction object itself.
ExecuteTransactionAsync<TResult>(Func<CancellationToken, Task<TResult>>) Same as above, but returns a result. When the unit of work produces a value.
ExecuteTransactionAsync(Func<IDbContextTransaction, CancellationToken, Task>) Runs work inside a transaction and passes the active transaction to the callback. When lower-level APIs need direct transaction access.
ExecuteTransactionAsync<TResult>(Func<IDbContextTransaction, CancellationToken, Task<TResult>>) Same as above, but returns a result. When you need both transaction access and a computed value.

Example

using TinyHelpers.EntityFrameworkCore.Extensions;

await context.ExecuteTransactionAsync(async cancellationToken =>
{
    context.Add(new Order { Id = 1 });
    await context.SaveChangesAsync(cancellationToken);
});

Vector columns

VectorAttribute

Marks a property or field as a vector column.

Use it when your database provider supports vector types and you want the mapping intent to live directly on the entity member.

Example

using System.ComponentModel.DataAnnotations.Schema;

public sealed class Document
{
    public int Id { get; set; }

    [Vector(1536)]
    public float[] Embedding { get; set; } = [];
}

Quick examples

JSON-backed property mapping

using Microsoft.EntityFrameworkCore;
using TinyHelpers.EntityFrameworkCore.Extensions;

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>(builder =>
    {
        builder.Property(x => x.Metadata).HasJsonConversion();
    });
}

String collection mapping

using Microsoft.EntityFrameworkCore;
using TinyHelpers.EntityFrameworkCore.Extensions;

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>(builder =>
    {
        builder.Property(x => x.Tags).HasArrayConversion(",");
    });
}

Global soft-delete filter

using Microsoft.EntityFrameworkCore;
using TinyHelpers.EntityFrameworkCore.Extensions;

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyQueryFilter<ISoftDeletable>(e => !e.IsDeleted);
}

Contribute

The project is continuously evolving. Contributions, issues, and pull requests are welcome.

Work on the develop branch, not on master. Pull requests should target develop.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  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

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.0.78 37 6/18/2026
3.0.76 101 6/10/2026
3.0.71 125 5/22/2026
3.0.70 144 4/15/2026
3.0.69 555 3/12/2026
3.0.65 278 3/11/2026
3.0.64 305 2/11/2026
3.0.62 280 1/14/2026
3.0.61 520 12/10/2025
3.0.60 620 11/13/2025
3.0.58 1,708 10/15/2025
3.0.56 10,378 9/10/2025
3.0.54 699 9/1/2025
3.0.52 705 7/30/2025
3.0.51 1,206 7/9/2025
3.0.49 643 6/11/2025
3.0.48 1,931 5/14/2025
3.0.47 2,574 4/9/2025
3.0.46 559 3/18/2025
3.0.45 350 3/12/2025
Loading failed