Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework cannot bind value object in entity constructor

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 };
    }
}
like image 831
JakeAM Avatar asked Apr 18 '19 15:04

JakeAM


People also ask

Can entities have constructors?

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.

What is not mapped in C#?

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. {

Does EF core need empty constructor?

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.

What is DbSet in Entity Framework Core?

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.


1 Answers

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.

like image 82
Ivan Stoev Avatar answered Sep 24 '22 13:09

Ivan Stoev