Entity Framework Core 2.1 - 拥有类型和嵌套值对象
Posted
技术标签:
【中文标题】Entity Framework Core 2.1 - 拥有类型和嵌套值对象【英文标题】:Entity Framework Core 2.1 - owned types and nested value objects 【发布时间】:2021-10-19 17:53:48 【问题描述】:我正在学习 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;
当我尝试在我的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");
);
);
我收到以下错误:
表达式“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");
);
但这也导致:
表达式“x => x.Status.ExpirationDate”不是有效的属性表达式。该表达式应该表示一个简单的属性访问:'t => t.MyProperty'。
我也试过了:
modelBuilder.Entity<Customer>()
.OwnsOne(p => p.Status,
cb => cb.OwnsOne(c => c.ExpirationDate));
但也没有运气......无论如何,任何帮助将不胜感激,如果有人能解释为什么我的尝试都不起作用,如果可能的话,那将是非常棒的?提前致谢!
更新
首先按照 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();
更新
只需要在 CustomerStatus
类内的 Type
和 ExpirationDate
属性上添加私有设置器,并结合 Ivan 的答案,它就像一个魅力。非常感谢!
【问题讨论】:
【参考方案1】:您的尝试无效,因为拥有的类型只能通过它们的 owner 实体进行配置,更具体地说,通过 OwnsOne
方法返回的它们自己的构建器或作为所有者实体构建器的OwnsOne
方法的Action<T>
参数的参数提供。
所以配置应该是这样的(注意嵌套的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");
);
);
);
【讨论】:
感谢您的快速回复和解释,但是当我按照说明进行操作时,我收到了新错误,其中指出:实体类型“CustomerStatus”的“字段”以上是关于Entity Framework Core 2.1 - 拥有类型和嵌套值对象的主要内容,如果未能解决你的问题,请参考以下文章
Entity Framework core 2.1 多对多选择查询
使用 Entity Framework Core (2.1) 调用标量函数的最佳实践
Entity Framework Core 2.1 无法更新具有关系的实体