✅ [EF Core] ValueObject Mapping thinks ValueObject is a normal Entity
Problem:
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.
// 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();
}
1 Reply
I noticed that
modelBuilder._builder._entityTypes
contains UpdateQueueStatus
, even tho there is no dbset of it
modelBuilder.Ignore<UpdateQueueStatus>();
solved the problem