TinyHelpers.EntityFrameworkCore
3.0.76
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
<PackageReference Include="TinyHelpers.EntityFrameworkCore" Version="3.0.76" />
<PackageVersion Include="TinyHelpers.EntityFrameworkCore" Version="3.0.76" />
<PackageReference Include="TinyHelpers.EntityFrameworkCore" />
paket add TinyHelpers.EntityFrameworkCore --version 3.0.76
#r "nuget: TinyHelpers.EntityFrameworkCore, 3.0.76"
#:package TinyHelpers.EntityFrameworkCore@3.0.76
#addin nuget:?package=TinyHelpers.EntityFrameworkCore&version=3.0.76
#tool nuget:?package=TinyHelpers.EntityFrameworkCore&version=3.0.76
Tiny Helpers for Entity Framework Core
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
- Property builder helpers
- Query filters
- Transaction helpers
- Vector columns
- Quick examples
- Contribute
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 | Versions 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. |
-
net10.0
- Microsoft.EntityFrameworkCore.Relational (>= 10.0.9)
- TinyHelpers (>= 3.3.25)
-
net8.0
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.28)
- TinyHelpers (>= 3.3.25)
-
net9.0
- Microsoft.EntityFrameworkCore.Relational (>= 9.0.17)
- TinyHelpers (>= 3.3.25)
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 |