TinyHelpers.EntityFrameworkCore 3.0.78

dotnet add package TinyHelpers.EntityFrameworkCore --version 3.0.78
                    
NuGet\Install-Package TinyHelpers.EntityFrameworkCore -Version 3.0.78
                    
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.78" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="TinyHelpers.EntityFrameworkCore" Version="3.0.78" />
                    
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.78
                    
#r "nuget: TinyHelpers.EntityFrameworkCore, 3.0.78"
                    
#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.78
                    
#: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.78
                    
Install as a Cake Addin
#tool nuget:?package=TinyHelpers.EntityFrameworkCore&version=3.0.78
                    
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 persistence intent of your Entity Framework Core model close to the entity type or model configuration 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 Entity Framework 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 Entity Framework Core change tracking aligned with the persisted representation.

JsonStringConverter<T>

Converts a CLR object graph to and from a JSON string for storage in a text column.

Use it when a value object or small object graph belongs to the entity and should live in one 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 Entity Framework Core detects changes based on serialized content instead of object reference identity, avoiding redundant updates when two values serialize to the same payload.

StringArrayConverter

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

Use it when a small string collection should stay on the entity row and does not need independent relational querying.

StringArrayComparer

Compares string sequences by content and order.

Use it together with StringArrayConverter so Entity Framework Core treats two collections as equal when they contain the same values in the same order, even when the collection instances are different.

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 conversion and comparison pieces together so model configuration can state persistence intent once while Entity Framework Core still receives the metadata it needs for materialization and change tracking.

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 serialized-value change tracking. When a value object or small object graph should be persisted in a single text column.
HasArrayConversion(this PropertyBuilder<IEnumerable<string>>) Stores a string sequence as a single delimited column and tracks sequence content. When the property is exposed as IEnumerable<string> and does not need a separate relational table.
HasArrayConversion(this PropertyBuilder<string[]>) Stores a string array as a single delimited column and tracks sequence content. When the property is exposed as string[] and does not need a separate relational table.
IsVector(this PropertyBuilder, int size = 1536) Maps the property to a vector column type with the specified dimension. 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 centralize model-wide conventions such as soft delete, tenant isolation, or visibility rules so each entity type does not need duplicate configuration.

Method What it does When to use it
ApplyQueryFilter<TEntity>(Expression<Func<TEntity, bool>>) Applies the same filter to all mapped 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 mapped entity types that expose a property with the given name and type. When entities do not share a type but expose the same shadow or CLR property.
ApplyQueryFilter<TEntity>(string filterName, Expression<Func<TEntity, bool>>) .NET 10+ named filter overload. When you want to selectively disable one filter later, such as soft delete without disabling tenant isolation.
ApplyQueryFilter<TType>(string filterName, string propertyName, TType value) .NET 10+ named filter overload for a property match. When a shared property drives a filter that may need to be disabled independently.
GetEntityTypes<TType>() Returns the mapped CLR entity types assignable to TType. When you need the model types behind a base type or interface.
GetEntityTypes(Type baseType) Returns the mapped 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 Entity Framework Core execution strategies and explicit transactions so retry behavior stays consistent and transaction boilerplate stays out of repositories and services.

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. The callback decides whether and when to commit it. When lower-level APIs need direct transaction access or custom commit timing.
ExecuteTransactionAsync<TResult>(Func<IDbContextTransaction, CancellationToken, Task<TResult>>) Same as above, but returns a result. When you need both transaction access, custom commit timing, 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 0 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 547 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,354 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,922 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