Exe*_*lol 4 c# domain-driven-design value-objects entity-framework-core-2.1 owned-types
我正在学习DDD,并且当前正在使用的教程是使用NHibernate实现的,但是由于缺乏经验,我决定使用EF Core 2.1来完成本课程。
但是,我目前对以下内容有些困惑:我有三个类Customer,它们是一个实体和两个值对象(CustomerStatus在其中的值对象ExpirationDate)-像这样:
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; }
}
Run Code Online (Sandbox Code Playgroud)
当我尝试在我的内部执行以下操作时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");
});
});
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
表达式“ x => x.ExpirationDate.Date”不是有效的属性表达式。该表达式应表示一个简单的属性访问:“ t => t.MyProperty”。
参数名称:propertyAccessExpression'
除此之外,我还尝试做以下事情:
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");
});
Run Code Online (Sandbox Code Playgroud)
但这也会导致:
表达式“ x => x.Status.ExpirationDate”不是有效的属性表达式。该表达式应表示一个简单的属性访问:“ t => t.MyProperty”。
我也尝试过:
modelBuilder.Entity<Customer>()
.OwnsOne(p => p.Status,
cb => cb.OwnsOne(c => c.ExpirationDate));
Run Code Online (Sandbox Code Playgroud)
但是也没有运气...无论如何,任何帮助将不胜感激,如果可能的话,如果有人可以解释为什么我的尝试都没有奏效的话,那将是非常伟大的?提前致谢!
更新
首先按照Ivan的评论中所述进行操作后,我收到有关CustomerStatus类构造函数的错误,因此我添加了默认受保护的类。
之后,我开始出现错误:
实体类型“ CustomerStatus”的字段“ k__BackingField”是只读的,因此无法设置。
CustomerStatus如果有帮助,这是我课程的内部内容:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
更新
它所要做的只是在类中添加了私有的setter Type和ExpirationDate属性,CustomerStatus并结合了Ivan的答案,它就像一种魅力。非常感谢!
您的尝试不起作用,因为只能通过其所有者实体(尤其是通过OwnsOne方法返回的或作为所有者实体构建器Action<T>的OwnsOne方法的参数的自变量提供)的自身构建器来配置拥有的类型。
因此配置应如下所示(请注意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");
});
});
});
Run Code Online (Sandbox Code Playgroud)