使用 EF 核心将 table 行映射到 DDD 值对象
Map table row to DDD value object woith EF core
场景
我的微服务域模型中有两个聚合:User 和 UserNotification。
public class User : Aggreagete
{
public int Id { get; private set; }
}
public class UserNotification : Aggreagete
{
public int Id { get; private set; }
public int UserId { get; private set; }
public bool EnableSms { get; private set; }
public bool EnableEmail { get; private set; }
public NotificationKind NotificationKind { get; private set; }
public UserModel User { get;private set }
}
UserValueObject 需要从与用户聚合相同的 table 进行映射。我使用 UserValueObject 因为从 Notification bounded Context 它需要是 immutable.
我有以下 EF 映射:
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("Users", SCHEME);
builder.HasKey(o => o.Id);
builder.Property(o => o.Id);
builder.HasMany<UserNotification>()
.WithOne()
.HasForeignKey(entry => entry.UserId)
.OnDelete(DeleteBehavior.Cascade);
}
public void Configure(EntityTypeBuilder<UserNotification> builder)
{
builder.ToTable("UserNotifications", SCHEME);
builder.HasKey(o => o.Id);
builder.Property(o => o.Id);
builder.Property(e => e.UserId).IsRequired();
builder.Property(e => e.EnableSms).IsRequired();
builder.Property(e => e.EnableEmail).IsRequired();
builder.Property(e => e.NotificationKind).IsRequired()
.HasConversion(
v => v.ToString(),
strValue => Enum.Parse<NotificationKind>(strValue)
);
builder.OwnsOne(e => e.User).ToTable("Users");
}
问题
我在 "Add Migration"
期间收到错误消息
Cannot use table 'dbo.Users' for entity type 'User' since it is being used for entity type 'UserModel' and there is no relationship between their primary keys.
用户模型是:
public class UserModel : ValueObject
{
public int Id { get; private set; }
public string Email { get; private set; }
public string Phone { get; private set; }
public string Name { get; private set; }
}
问题
我想从数据库 table "Users" 映射 UserModel.Id,但是电子邮件、Phone 和名称应该使用对身份的 HTTP 请求注入到存储库中
服务。是否可以使用 EF 核心进行此类操作?
我发现用拥有的实体不可能实现这一点,因为用户 table 也用于映射其他聚合。
由于名称冲突,您得到了正确的异常。
对于 User
实体,您要求 EF 使用 Users
table:
builder.ToTable("Users", SCHEME);
但您还要求它使用相同的 table 来存储 UserNotification
实体的值对象:
builder.OwnsOne(e => e.User).ToTable("Users");
如果您的计划是 "reuse" Users
聚合持久性以神奇地将价值项目映射到它,那么我可以肯定地说这不是一个好主意。
值对象是类型化的状态片段。它们属于实体,由实体管理。你必须在需要时更新VO的内容。
您也不需要将用户信息保存在聚合中,除非您在通知聚合的任何方法中使用它。如果您需要能够查询和加入 - 只需在查询中执行即可。不要使用 EF 进行查询,而是编写带有内部联接的普通 SQL 来获取您需要的信息。查查 CQRS,Jimmy Bogard 提倡使用 EF 作为写入端,前段时间使用普通 SQL 查询作为读取端,这完全有道理。
场景
我的微服务域模型中有两个聚合:User 和 UserNotification。
public class User : Aggreagete
{
public int Id { get; private set; }
}
public class UserNotification : Aggreagete
{
public int Id { get; private set; }
public int UserId { get; private set; }
public bool EnableSms { get; private set; }
public bool EnableEmail { get; private set; }
public NotificationKind NotificationKind { get; private set; }
public UserModel User { get;private set }
}
UserValueObject 需要从与用户聚合相同的 table 进行映射。我使用 UserValueObject 因为从 Notification bounded Context 它需要是 immutable.
我有以下 EF 映射:
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("Users", SCHEME);
builder.HasKey(o => o.Id);
builder.Property(o => o.Id);
builder.HasMany<UserNotification>()
.WithOne()
.HasForeignKey(entry => entry.UserId)
.OnDelete(DeleteBehavior.Cascade);
}
public void Configure(EntityTypeBuilder<UserNotification> builder)
{
builder.ToTable("UserNotifications", SCHEME);
builder.HasKey(o => o.Id);
builder.Property(o => o.Id);
builder.Property(e => e.UserId).IsRequired();
builder.Property(e => e.EnableSms).IsRequired();
builder.Property(e => e.EnableEmail).IsRequired();
builder.Property(e => e.NotificationKind).IsRequired()
.HasConversion(
v => v.ToString(),
strValue => Enum.Parse<NotificationKind>(strValue)
);
builder.OwnsOne(e => e.User).ToTable("Users");
}
问题
我在 "Add Migration"
期间收到错误消息Cannot use table 'dbo.Users' for entity type 'User' since it is being used for entity type 'UserModel' and there is no relationship between their primary keys.
用户模型是:
public class UserModel : ValueObject
{
public int Id { get; private set; }
public string Email { get; private set; }
public string Phone { get; private set; }
public string Name { get; private set; }
}
问题
我想从数据库 table "Users" 映射 UserModel.Id,但是电子邮件、Phone 和名称应该使用对身份的 HTTP 请求注入到存储库中 服务。是否可以使用 EF 核心进行此类操作? 我发现用拥有的实体不可能实现这一点,因为用户 table 也用于映射其他聚合。
由于名称冲突,您得到了正确的异常。
对于 User
实体,您要求 EF 使用 Users
table:
builder.ToTable("Users", SCHEME);
但您还要求它使用相同的 table 来存储 UserNotification
实体的值对象:
builder.OwnsOne(e => e.User).ToTable("Users");
如果您的计划是 "reuse" Users
聚合持久性以神奇地将价值项目映射到它,那么我可以肯定地说这不是一个好主意。
值对象是类型化的状态片段。它们属于实体,由实体管理。你必须在需要时更新VO的内容。
您也不需要将用户信息保存在聚合中,除非您在通知聚合的任何方法中使用它。如果您需要能够查询和加入 - 只需在查询中执行即可。不要使用 EF 进行查询,而是编写带有内部联接的普通 SQL 来获取您需要的信息。查查 CQRS,Jimmy Bogard 提倡使用 EF 作为写入端,前段时间使用普通 SQL 查询作为读取端,这完全有道理。