问题
I'm learning DDD and the tutorial I'm currently following is implemented using NHibernate, but since my lack of experience with it I've decided to go through the course using EF Core 2.1.
However, I'm currently a bit stuck with the following: I have three classes Customer
which is an entity and two value objects (CustomerStatus
and inside of it value object ExpirationDate
) - like this:
public class Customer : Entity
{
//... constructor, other properties and behavior omitted for the sake of simplicity
public CustomerStatus Status { get; set; }
}
public class CustomerStatus : ValueObject<CustomerStatus>
{
// customer status is enum containing two values (Regular,Advanced)
public CustomerStatusType Type { get; }
public ExpirationDate ExpirationDate { get; }
}
public class ExpirationDate : ValueObject<ExpirationDate>
{
//... constructor, other properties and behavior omitted for the sake of simplicity
public DateTime? Date { get; private set; }
}
When I try to do the following inside of my DbContext
:
modelBuilder.Entity<Customer>(table =>
{
table.OwnsOne(x => x.Status,
name =>
{
name.Property(x => x.ExpirationDate.Date).HasColumnName("StatusExpirationDate");
name.Property(x => x.Type).HasColumnName("Status");
});
});
I'm getting the following error:
The expression 'x => x.ExpirationDate.Date' is not a valid property expression. The expression should represent a simple property access: 't => t.MyProperty'.
Parameter name: propertyAccessExpression'
Beside this I've tried doing things like:
table.OwnsOne(x => x.Status.ExpirationDate,
name =>
{
name.Property(x => x.Date).HasColumnName("StatusExpirationDate");
});
table.OwnsOne(x => x.Status,
name =>
{
name.Property(x => x.Type).HasColumnName("Status");
});
But it also leads to:
The expression 'x => x.Status.ExpirationDate' is not a valid property expression. The expression should represent a simple property access: 't => t.MyProperty'.
I've also tried:
modelBuilder.Entity<Customer>()
.OwnsOne(p => p.Status,
cb => cb.OwnsOne(c => c.ExpirationDate));
But with no luck as well... Anyways, any help would be greatly appreciated, also if possible it would be really great if someone could explain why none of my tries are not working? Thanks in advance!
UPDATE
After doing as stated in Ivan's comment first I was getting error about CustomerStatus
class constructor so I've added default protected one.
After that I started getting error:
Field 'k__BackingField' of entity type 'CustomerStatus' is readonly and so cannot be set.
Here's inner of my CustomerStatus
class if it helps:
public class CustomerStatus : ValueObject<CustomerStatus>
{
public CustomerStatusType Type { get; }
public ExpirationDate ExpirationDate { get; }
public static readonly CustomerStatus Regular =
new CustomerStatus(CustomerStatusType.Regular, ExpirationDate.Infinite);
public bool IsAdvanced => Type == CustomerStatusType.Advanced && !ExpirationDate.IsExpired;
private CustomerStatus(CustomerStatusType type, ExpirationDate expirationDate)
{
Type = type;
ExpirationDate = expirationDate;
}
protected CustomerStatus()
{
}
public static CustomerStatus Create(CustomerStatusType type, ExpirationDate expirationDate)
{
return new CustomerStatus(type, expirationDate);
}
public CustomerStatus Promote()
{
return new CustomerStatus(CustomerStatusType.Advanced, ExpirationDate.Create(DateTime.UtcNow.AddYears(1)).Value);
}
protected override bool EqualsCore(CustomerStatus other)
{
return Type == other.Type && ExpirationDate == other.ExpirationDate;
}
protected override int GetHashCodeCore()
{
return Type.GetHashCode() ^ ExpirationDate.GetHashCode();
}
}
UPDATE
All it took was adding private setters on Type
and ExpirationDate
properties inside of CustomerStatus
class and in combination with Ivan's answer it works like a charm. Thanks a lot!
回答1:
Your attempts are not working because owned types can only be configured through their owner entity, and more specifically, through their own builder returned by the OwnsOne
method or provided as an argument of the Action<T>
argument of the OwnsOne
method of the owner entity builder.
So the configuration should be something like this (note the nested OwnsOne
):
modelBuilder.Entity<Customer>(customer =>
{
customer.OwnsOne(e => e.Status, status =>
{
status.Property(e => e.Type).HasColumnName("Status");
status.OwnsOne(e => e.ExpirationDate, expirationDate =>
{
expirationDate.Property(e => e.Date).HasColumnName("StatusExpirationDate");
});
});
});
来源:https://stackoverflow.com/questions/53652135/entity-framework-core-2-1-owned-types-and-nested-value-objects