I want to use value objects as properties in my project (in my project value objects are C# 9 record types).
The entity looks like this:
public class Client : IEntity
{
public int Id { get; set; }
public ClientId ClientId { get; set; }
}
And ClientId
value object:
public record ClientId
{
private readonly byte[] _bytes;
public ClientId(byte[] bytes)
{
if (bytes is null || bytes.Length != 32)
throw new ArgumentException($"'{nameof(bytes)}' must be 32 bytes long");
_bytes = bytes;
}
public string Value => Base64UrlEncoder.Encode(_bytes);
}
When I do migration I get an following error:
No suitable constructor was found for entity type 'ClientId'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'bytes' in 'ClientId(byte[] bytes)'; cannot bind 'original' in 'ClientId(ClientId original)'.
I know that this error occurs because I don't have empty constructor, but I really don't want to have it because I want to validate the length of given _bytes
. What's more, even when I have added this empty constructor:
public record ClientId
{
private readonly byte[] _bytes;
public ClientId()
{
}
public ClientId(byte[] bytes)
{
if (bytes is null || bytes.Length != 32)
throw new ArgumentException($"'{nameof(bytes)}' must be 32 bytes long");
_bytes = bytes;
}
public string Value => Base64UrlEncoder.Encode(_bytes);
}
I get the error:
The entity type 'ClientId' 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.
It seems to me that EF Core treats the record
type as another entity and wants to create a relationship.
What am I doing wrong?
You have to use Value Conversions.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Client>()
.Property(e => e.ClientId)
.HasConversion(
v => v.Value,
v => new ClientId(Base64UrlEncoder.DecodeBytes(v)));
}
In this case, the default constructor is not needed.