79722745

Date: 2025-08-01 16:12:49
Score: 1
Natty:
Report link

For anyone who has the same problem

Finally, the issue was not caused by Mapster or HotChocolate, but it was a misconfiguration for DDD ValueObject for EF itself.

Instead of

public static class AdminModelBuilderExtension
{
    public static void ConfigureAdminModule(this ModelBuilder modelBuilder)
    {    
        modelBuilder.Entity<LegalEntity>(entity =>
        {
            entity
                .Property(le => le.Label)
                .HasConversion(le => le.Value, v => Label.Create(v).Value);

            entity.HasIndex(le => le.Label).IsUnique();
        });
    }
}

The well suited configuration for a DDD is by using ComplexProperty, as mentionned for example in this article

In my case, the configuration has switch to

public static class AdminModelBuilderExtension
{
    public static void ConfigureAdminModule(this ModelBuilder modelBuilder)
    {    
        modelBuilder.Entity<LegalEntity>(entity =>
        {
            entity.ComplexProperty(
                le => le.Label,
                label =>
                    label
                        .Property(l => l.Value)
                        .HasColumnName(StringHelper.ToSnakeCase(nameof(LegalEntity.Label)))

            // Index cannot be created on complexProperty
            // They are instead manually created in the migration
            // https://github.com/dotnet/efcore/issues/17123
        });
    }
}

However, as you can see, EF fluent API doesn't allow to set index directly on complexProperty. Those index must be created manually in your migration file.

Working with that setup, all previous

LegalEntity? test = await dbContext
    .LegalEntities.OrderBy(le => le.Label)
    .FirstOrDefaultAsync(CancellationToken.None);

doesn't work anymore, and should always be updated to

LegalEntity? test = await dbContext
    .LegalEntities.OrderBy(le => le.Label.Value)
    .FirstOrDefaultAsync(CancellationToken.None);
Reasons:
  • Blacklisted phrase (1): this article
  • Long answer (-1):
  • Has code block (-0.5):
  • Self-answer (0.5):
  • Low reputation (1):
Posted by: Rémi Lamotte