Entity Framework cannot bind value object in entity constructor

c# entity-framework-core

Question

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 };
    }
}
1
0
4/18/2019 3:54:05 PM

Accepted Answer

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.

2
4/18/2019 5:00:31 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow