Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
In EFCore3 custom ValueConverters don't force client-side evaluation!
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace EFCore.Conversions
{
public readonly struct StrongId : IEquatable<StrongId>
{
public Guid RawValue { get; }
public StrongId(Guid rawValue)
{
RawValue = rawValue;
}
public bool Equals(StrongId other) => RawValue == other.RawValue;
public override bool Equals(object? obj) => obj is StrongId d && Equals(d);
public override int GetHashCode() => RawValue.GetHashCode();
public override string ToString() => RawValue.ToString("N");
public static bool operator ==(StrongId left, StrongId right) => left.RawValue == right.RawValue;
public static bool operator !=(StrongId left, StrongId right) => left.RawValue != right.RawValue;
public static explicit operator Guid(StrongId d) => d.RawValue;
public static explicit operator StrongId(Guid d) => new StrongId(d);
}
class Program : IHostedService
{
static async Task Main(string[] args)
{
await Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddDbContext<CoreContext>(cfg =>
cfg.UseSqlServer("Server=localhost,1433;User Id=sa;Password=yourStrong(!)Password;Database=App"));
services.AddTransient<IHostedService, Program>();
})
.RunConsoleAsync();
}
private readonly CoreContext dbContext;
public Program(CoreContext dbContext)
{
this.dbContext = dbContext;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
await dbContext.Database.EnsureCreatedAsync();
var g = Guid.NewGuid();
await dbContext.Entities
.Where(d => d.Id == new StrongId(g))
.ToListAsync();
}
public Task StopAsync(CancellationToken cancellationToken)
{
return dbContext.Database.EnsureDeletedAsync();
}
}
public class Entity
{
public StrongId Id { get; set; }
}
public class CoreContext : DbContext
{
public DbSet<Entity> Entities => Set<Entity>();
public CoreContext(DbContextOptions<CoreContext> options)
: base(options)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Entity>(b =>
{
b.HasKey(e => e.Id);
b.Property(e => e.Id)
.ValueGeneratedNever()
.HasConversion(new StrongIdConverter());
// Or:
// .HasConversion(
// e => e.RawValue,
// e => new StrongId(e));
});
}
public class StrongIdConverter : ValueConverter<StrongId, Guid>
{
public StrongIdConverter()
: base(
e => e.RawValue,
e => new StrongId(e),
null)
{ }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment