在EFCore中,我何时需要在值对象中添加[Owned]特性?

报错内容:System.InvalidOperationException:"The entity type 'xxx' cannot be configured as owned because it has already been configured as a non-owned. If you want to override previous configuration first remove the entity type from the model by calling 'Ignore'.

原因:我在实体中添加了一个值对象。值对象如下:

有一个枚举类型的属性Weekday,由于显式得未配置 [Owned] 特性 导致报错

cs 复制代码
    public class WeeklyLoopTimeStamp:ValueObject
    {
        // 日期
        public DayOfWeek Weekday
        {
            get; set;
        }
        // 时间
        public DateTime TimePoint
        {
            get; set;
        }

        protected override IEnumerable<object> GetAtomicValues()
        {
            yield return Weekday;
            yield return TimePoint;
        }
    }

在EF Core中,当你想要将属性标记为值对象,并且希望EF Core将其配置为复合类型(Complex Type)时,你需要在值对象的属性上添加[Owned]特性。

添加[Owned]特性的好处是,EF Core会自动处理该属性与其所属实体之间的映射和关系。它简化了代码,并减少了手动配置的工作量。

然而,并非所有情况下都需要添加[Owned]特性。以下是一些情况说明:

  1. 当属性的数据类型本身是一个简单的值类型(如string、int、DateTime等)时,EF Core会自动将其视为复合类型的一部分,无需添加[Owned]特性。

  2. 当属性的数据类型是自定义的类或结构体,并且你希望将其视为独立的实体类型(拥有自己的唯一标识符),而不是复合类型时,你不需要添加[Owned]特性。

  3. 当属性是一个集合类型(如List、ICollection等)时,EF Core会自动将其配置为导航属性,不需要添加[Owned]特性。

所以,只有当你确实希望将属性配置为值对象并作为复合类型存储在同一个数据库表中时,才需要在值对象的属性上添加[Owned]特性。

如果没有添加[Owned]特性而不报错,很可能是由于EF Core的默认行为能够正确地推断出属性应该被视为复合类型。然而,为了明确你的意图并提高代码的清晰度,建议在值对象的属性上显式添加[Owned]特性

拓展问题:

1. 值对象在数据表中以何种结构被存储?

在数据库中,如果一个实体拥有一个值对象属性,通常会将该值对象的属性作为实体表中的进行存储。

简单理解为:值对象的属性会被提取到实体属性中,从而成为单独的一列

对于你提到的WxTemplateForPlanOrderEntity实体,如果WeeklyLoopTimeStamp是一个值对象属性,那么通常会根据数据库的设计,创建一个包含WeeklyLoopTimeStamp属性的列。

具体地,可以根据你所使用的数据库类型和ORM框架的要求,将WeeklyLoopTimeStamp属性的值序列化为适当的数据类型(例如字符串、JSON等),并将其存储在数据库表的相应列中。

例如,在关系型数据库中,你可以将WeeklyLoopTimeStamp属性的值以JSON格式序列化,并将其存储为varchar或json类型的列。在NoSQL数据库中,可能会选择直接将WeeklyLoopTimeStamp属性的值存储为文档或字段的形式。

需要注意的是,数据库中的列与实体的属性之间需要进行映射关系的配置。这通常由ORM框架负责处理,通过特定的注解、配置文件或代码来定义实体属性与数据库列之间的映射关系。

综上所述,数据库的存储方式取决于数据库类型、ORM框架和相关配置,但一般来说,值对象属性会被作为实体表中的单独列进行存储。

2. 如果实体下的值对象是一对多关系?数据表中会如何存储?

例子:

cs 复制代码
    /// <summary>
    /// 发送数据时机 按周循环
    /// </summary>
    public List<WeeklyLoopTimeStamp> WeeklyLoopTimeStamp
    {
        get;
        set;
    }

那么需要根据ORM来配置,一般会创建一张另外的关联表。外键与实体相关联。

cs 复制代码
builder.OwnsMany( );

具体传入的配置方法需要根据项目规范制定。

相关推荐
若兰幽竹13 分钟前
【从零开始编写数据库:基于Python语言实现数据库ToyDB的ACID特性】
数据库·python
宇钶宇夕15 分钟前
S7-200 SMART CPU 密码清除全指南:从已知密码到忘记密码的解决方法
运维·服务器·数据库·程序人生·自动化
周杰伦的稻香24 分钟前
MySQL密码管理器“mysql_config_editor“
数据库·mysql
云朵大王28 分钟前
SQL 视图与事务知识点详解及练习题
java·大数据·数据库
czhc11400756631 小时前
LINUX712 MYSQL;磁盘分区;NFS
数据库·mysql·adb
不太可爱的大白2 小时前
Mysql:分库分表
数据库·mysql
十五年专注C++开发2 小时前
hiredis: 一个轻量级、高性能的 C 语言 Redis 客户端库
开发语言·数据库·c++·redis·缓存
bianguanyue3 小时前
SQLite密码修改故障排查:RSA加密随机性导致的数据库匹配问题
数据库·sqlite·c#
亚马逊云开发者4 小时前
将 Go 应用从 x86 平台迁移至 Amazon Graviton:场景剖析与最佳实践
linux·数据库·golang
张先shen4 小时前
亿级流量下的缓存架构设计:Redis+Caffeine多级缓存实战
数据库·redis·缓存