I've created an entity that takes a value object as a parameter in it's constructor, however when I add the entity to the db context it throws the following exception.
InvalidOperationException: No suitable constructor found for entity type >'BasketItem'. The following constructors had parameters that could not be >bound to properties of the entity type: cannot bind 'price' in >'BasketItem(Guid id, Guid productId, DateTimeOffset addedAt, Money price)'.
I've tried builder.OwnsOne(x => x.Price);
in the type configuration. Keep in mind that I am using the in memory storage provider.
BasketItem.cs
public sealed class BasketItem : Entity
{
public Guid ProductId { get; private set; }
public DateTimeOffset AddedAt { get; private set; }
public Money Price { get; private set; }
public BasketItem(Guid id, Guid productId, DateTimeOffset addedAt, Money price) : base(id)
{
ProductId = productId;
AddedAt = addedAt;
Price = price;
}
}
Money.cs
public sealed class Money : ValueObject
{
public decimal Value { get; private set; }
public string CurrencyCode { get; private set; }
public Money(decimal value, string currencyCode)
{
Value = value;
CurrencyCode = currencyCode;
}
protected override IEnumerable<object> GetAtomicValues()
{
return new object[] { Value, CurrencyCode };
}
}
It's possible to define a constructor with parameters and have EF Core call this constructor when creating an instance of the entity. The constructor parameters can be bound to mapped properties, or to various kinds of services to facilitate behaviors like lazy-loading.
The NotMapped attribute is used to specify that an entity or property is not to be mapped to a table or column in the database. In the following example, the AuditLog class will not be mapped to a table in the database: public class Contact. {
EF Core cannot set navigation properties (such as Blog or Posts above) using a constructor. However, this protected empty constructor is something we would like to get rid of, when designing a clean DDD domain entity.
In Entity Framework Core, the DbSet represents the set of entities. In a database, a group of similar entities is called an Entity Set. The DbSet enables the user to perform various operations like add, remove, update, etc. on the entity set.
Implementing DDD value objects with EF Core owned entity types has several shortcomings, caused by the fact that EF Core owned entity types are still considered entities, and properties returning owned entity types are treated as navigation properties.
In this particular case, the issue is caused by the last aforementioned thing along with the following Entity Type Constructors limitation
Some things to note:
- EF Core cannot set navigation properties (such as Blog or Posts above) using a constructor.
The workaround / solution is to provide special private constructor to be used by EF:
public BasketItem(Guid id, Guid productId, DateTimeOffset addedAt, Money price) : this(id, productId, addedAt)
{
Price = price;
}
/// <summary>
/// EF constructor
/// </summary>
private BasketItem(Guid id, Guid productId, DateTimeOffset addedAt) : base(id)
{
ProductId = productId;
AddedAt = addedAt;
}
And of course use [Owned]
attribute or OwnsOne
fluent API to map Money
as owned entity type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With