当前位置: 首页 > 知识库问答 >
问题:

原则2海关实体加载和持久化

曾永新
2023-03-14

是否可以在每个实体的基础上实施条令2中的自定义水合作用和持久性?

原则2对价值对象(如集合和ID)有一些主要限制。我想知道是否可以使用自定义机制(或实现)将对象属性映射到数据库(加载和持久化)。

我知道有一些可能“解决”这个问题,但我不喜欢其中任何一个:

  • 伪实体需要在实体中正确处理,从而将持久性层泄漏到域对象中

我知道条令中的生命周期事件可能是有用的。我无法确定postLoad事件是否携带一个已经构造好的实体对象(包含所有VO)?因为那样的话,我就没用了。

向你问好,斯皮甘德罗梅达

共有1个答案

翟青青
2023-03-14

是的,您可以在config/packages/doctor.yaml中注册新的水合器,如下所示:

doctrine:
    dbal: ...
    orm:
        hydrators:
            CustomEntityHydrator: 'App\ORM\Hydrator\CustomEntityHydrator'
            ...
        mapping: ...
        ...

然后,您可以在查询中使用它,如下所示:

php prettyprint-override">public function findCustomEntities(): array
{
    return $this->createQueryBuilder('c')
        ...your query logic...
        ->getResult('CustomEntityHydrator');
}

请注意,您只能为根实体指定要使用的名称或名称。如果获取关联的实体,最终可能会出现更复杂的设置,难以调试。

相反,您可以考虑只在实体的接口中处理值对象(VOs)。换句话说,字段是标量值,但是方法参数和返回值是VOs。

下面是一个实体的示例,该实体的id类型为Uuid、位置(一些数字标识符)、状态(例如三元真/假/空)。这些仅用于展示如何处理不同类型的值对象:

/**
 * @ORM\Entity()
 */
class CustomEntity
{
    /**
     * @ORM\Id()
     * @ORM\Column(type="string", length=64)
     */
    private string $id;

    /**
     * @ORM\Column(type="int")
     */
    private int $location;

    /**
     * @ORM\Column(type="bool, nullable=true)
     */
    private bool $status;

    private function __construct(Uuid $id, Location $location, Status $status)
    {
        $this->id = (string) $id;
        $this->location = $location->getValue();
        $this->status = $status->get();
    }

    public static function new(Location $location, Status $status): self
    {
        return new self(Uuid::v4(), $location, $status);
    }

    public function getId(): Uuid
    {
        return Uuid::fromString($this->id);
    }

    public function getLocation(): Location
    {
        return new Location($this->location);
    }

    public function activate(): void
    {
        $this->status = true;
    }

    public function deactivate(): void
    {
        $this->status = false;
    }

    public function isActive(): bool
    {
        $this->status === true;
    }

    public function isInactive(): bool
    {
        $this->status === false;
    }

    public function isUninitialized(): bool
    {
        $this->status === null;
    }

    public function getStatus(): Status
    {
        if ($this->status === null) {
            return new NullStatus();
        }
        if ($this->status === true) {
            return new ActiveStatus();
        }

        return new InactiveStatus();
    }
}

如您所见,您可以用公共构造函数替换new()。它的工作原理与二传手类似。我有时甚至在构造函数中为此使用(私有)setter。在这种情况下,如果您使用多个在内部设置值的方法,您甚至不需要设置器。类似地,在某些情况下,您可能希望返回标量值而不是VO(或者以另一种方式返回,如status getter和issers所示)。

关键是,从外部看,您的实体似乎会使用您的VO,但在内部,它已经切换到一种更适合ORM的表示形式。您甚至可以将其与使用VO和自定义类型(例如UUID)混合使用。您只需小心,当您的VO需要更多的信息来构建而不是存储在数据库中时,例如,如果我们示例中的数字位置在创建过程中也会使用区域设置,那么我们需要存储它(这很有意义,因为它似乎与数字id相关)或者我们必须在实体中硬编码它,或者在上面添加一个可以访问区域设置的抽象,在这种情况下,您的实体可能不会返回位置,或者至少不会返回LocalizedLocation。

您可能还想考虑对实体中的每一个属性没有VO。虽然它肯定会有帮助,例如,将电子邮件包装到自定义VO中以确保有效性,而不仅仅是字符串的类型提示,但对于(用户)名称这样的通用名称,它可能没有那么大的用处,因为名称种类繁多,所以它应该非常宽容地使用它所接受的字符串。使用上述方法,您可以在以后很容易地引入VO,方法是为VO添加新的getter、更改new()或任何其他改变属性的方法,然后不必更改以下数据模型中的任何内容(除非对值的表示方式有更大的更改)。

 类似资料:
  • 我希望在每次加载或持久化实体时包装/展开它。我知道我不能使用JPA监听器来完成这件事,因为它们只能对对象执行一个操作,而不能与其他对象交换它。自然的解决方案是使用方面。但是有没有特别的方法我可以切入呢?问题是要包装/解包装的实体可以是另一个实体的字段...

  • 我更新了实体文件以包含关系映射。

  • 对于新学生和新课程的情况,它工作得很好,但是在新课程和现有学生的情况下,我会从数据库中抛出一个唯一的约束冲突。关系类似于下面。 在持久化之前,我尝试使用entitymanager查找一个学生,如果该学生存在,则使用该实例而不是新的学生实例。这也不起作用,它仍然尝试执行插入而不是更新

  • 我有三个表在我的MySQL数据库,看起来像下面这些: 注意:我从那些表中删除了一些定义部分,比如AUTO_INCREMENT,以便使模式更简单。 我的问题是,我需要将这些表映射到实体类,比如和,但我不知道如何管理表中的列,以及如何管理实体中的这些关系。 我的第一个猜测是: 文件 文件 这些实体将生成我需要的三个表,但在表中没有我真正需要的列。把它放在那里很重要。我还可以创建第三个实体,例如,但我不

  • 我有一个奇怪的问题,我不认为这是正常的行为(至少我找不到任何关于它的提及,它似乎是不正确的)。这是我的关联映射: 当我获取一个节点实体使用: 条令也会加载相关的内容实体,没有明显的原因吗?我知道一对多的关系总是很紧张,但我不认为多对一关系是这样的吗? 我已经使用SQL logger准确地检查了正在发生的事情,我看到了对数据库的两个单独的查询。我没有在线听众或类似的东西。显式设置(默认设置)没有任何

  • 问题内容: 我有一个托管bean,其中包含当前页面的实体对象列表。在我创建一个新对象并在事务中使用persist()将其持久保存到数据库之后;在另一个事务中,当我调用merge时(由于该实体由于先前的事务提交而处于分离状态);实体管理器无法在持久性上下文中找到对象,并向数据库抛出选择查询。我是否缺少某些东西,或者是正常行为? 更新:当我使用mysql数据库和自动生成的ID列时,存在上述问题。当我在