© 2026 Hedgehog Software, LLC

TwitterGitHubDiscord
More
CommunitiesDocsAboutTermsPrivacy
Search
Star
Setup for Free
C#C
C#•3y ago•
2 replies
Ploxi

✅ [EF Core] ValueObject Mapping thinks ValueObject is a normal Entity

Problem:
dotnet ef migrations add mig_somename
dotnet ef migrations add mig_somename

Returns
The entity type 'UpdateQueueStatus' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.
The entity type 'UpdateQueueStatus' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.


// Mapping:
 modelBuilder.Entity<UpdateQueueEntry>(builder =>
{
    builder.HasKey(x => x.Id);

    // x.Status is a ValueObject. The underlying value is stored in the database as a string.
    // Converter is UpdateQueueStatusConverter
    builder
        .Property(x => x.Status)
        .HasConversion<string>(new UpdateQueueStatusConverter(), new UpdateQueueStatusComparer());
});

//Converters:
public class UpdateQueueStatusConverter : ValueConverter<UpdateQueueStatus, string>
{
    public UpdateQueueStatusConverter(ConverterMappingHints mappingHints = null) : base
    (
        v => v.Value,
        v => new UpdateQueueStatus(v),
        mappingHints
    )
    {
    }
}

public class UpdateQueueStatusComparer : ValueComparer<UpdateQueueStatus>
{
    public UpdateQueueStatusComparer() : base
    (
        equalsExpression: (c1, c2) => c1.Value == c2.Value,
        hashCodeExpression: c => c.Value.GetHashCode(),
        snapshotExpression: c => c.Value
    )
    {
    }
}

public class UpdateQueueEntry : IEntity<int>, ICreationTimeTracked
{
    private UpdateQueueEntry()
    {
    }

    public int Id { get; set; }
    public UpdateQueueStatus Status { get; set; }
}

public class UpdateQueueStatus
{
    public static readonly UpdateQueueStatus None = new UpdateQueueStatus("None");
    public static readonly UpdateQueueStatus Queued = new UpdateQueueStatus("Queued");

    // more statuses...

    public string Value { get; }

    public UpdateQueueStatus(string value)
    {
        Value = value;
    }

    public UpdateQueueStatus()
    {

    }

    // Removed for brevity: Implicit operators, equality, etc.

    public static implicit operator string(UpdateQueueStatus status);
    public static implicit operator UpdateQueueStatus(string value);
    public override string ToString();
    public static UpdateQueueStatus Parse(string value);
    public static bool operator ==(UpdateQueueStatus left, UpdateQueueStatus right);

    public static bool operator !=(UpdateQueueStatus left, UpdateQueueStatus right);

    public  bool Equals(UpdateQueueStatus? obj);
    public override bool Equals(object? obj);
    public override int GetHashCode();
}
 modelBuilder.Entity<UpdateQueueEntry>(builder =>
{
    builder.HasKey(x => x.Id);

    // x.Status is a ValueObject. The underlying value is stored in the database as a string.
    // Converter is UpdateQueueStatusConverter
    builder
        .Property(x => x.Status)
        .HasConversion<string>(new UpdateQueueStatusConverter(), new UpdateQueueStatusComparer());
});

//Converters:
public class UpdateQueueStatusConverter : ValueConverter<UpdateQueueStatus, string>
{
    public UpdateQueueStatusConverter(ConverterMappingHints mappingHints = null) : base
    (
        v => v.Value,
        v => new UpdateQueueStatus(v),
        mappingHints
    )
    {
    }
}

public class UpdateQueueStatusComparer : ValueComparer<UpdateQueueStatus>
{
    public UpdateQueueStatusComparer() : base
    (
        equalsExpression: (c1, c2) => c1.Value == c2.Value,
        hashCodeExpression: c => c.Value.GetHashCode(),
        snapshotExpression: c => c.Value
    )
    {
    }
}

public class UpdateQueueEntry : IEntity<int>, ICreationTimeTracked
{
    private UpdateQueueEntry()
    {
    }

    public int Id { get; set; }
    public UpdateQueueStatus Status { get; set; }
}

public class UpdateQueueStatus
{
    public static readonly UpdateQueueStatus None = new UpdateQueueStatus("None");
    public static readonly UpdateQueueStatus Queued = new UpdateQueueStatus("Queued");

    // more statuses...

    public string Value { get; }

    public UpdateQueueStatus(string value)
    {
        Value = value;
    }

    public UpdateQueueStatus()
    {

    }

    // Removed for brevity: Implicit operators, equality, etc.

    public static implicit operator string(UpdateQueueStatus status);
    public static implicit operator UpdateQueueStatus(string value);
    public override string ToString();
    public static UpdateQueueStatus Parse(string value);
    public static bool operator ==(UpdateQueueStatus left, UpdateQueueStatus right);

    public static bool operator !=(UpdateQueueStatus left, UpdateQueueStatus right);

    public  bool Equals(UpdateQueueStatus? obj);
    public override bool Equals(object? obj);
    public override int GetHashCode();
}
image.png
C# banner
C#Join
We are a programming server aimed at coders discussing everything related to C# (CSharp) and .NET.
61,871Members
Resources
Was this page helpful?

Similar Threads

Recent Announcements

Similar Threads

❔ Generic entity type in EF Core
C#CC# / help
4y ago
How to create entity correctly? [EF CORE]
C#CC# / help
2y ago
EF Core mapping to Viewmodels without duplicating viewmodels
C#CC# / help
6mo ago