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

Doctrine orm 原则2海关实体加载和持久化,doctrine-orm,doctrine,value-objects,Doctrine Orm,Doctrine,Value Objects,是否可以在每个实体的基础上实施条令2中的自定义水合作用和持久性 原则2对价值对象(如集合和ID)有一些主要限制。我想知道是否可以使用自定义机制(或实现)将对象属性映射到数据库(加载和持久化) 我知道有一些可能“解决”这个问题,但我不喜欢其中任何一个: 伪实体需要在实体中正确处理,从而将持久性层泄漏到域对象中 真正的实体需要更多的持久性工作(更多的存储库和更复杂的处理) 路堤具有上述限制 带有序列化的自定义DBAL类型使得无法查询某些值,或者至少查询速度非常慢 我知道条令中的生命周期事件可能是

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

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

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

  • 伪实体需要在实体中正确处理,从而将持久性层泄漏到域对象中
  • 真正的实体需要更多的持久性工作(更多的存储库和更复杂的处理)
  • 路堤具有上述限制
  • 带有序列化的自定义DBAL类型使得无法查询某些值,或者至少查询速度非常慢
我知道条令中的生命周期事件可能是有用的。我无法确定postLoad事件是否携带一个已经构造好的实体对象(包含所有VO)?因为那样的话,我就没用了

致以最良好的祝愿,
spigandromeda

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

原则:
dbal:。。。
orm:
水合器:
CustomEntityHydrotor:'App\ORM\Hydrotor\CustomEntityHydrotor'
...
映射:。。。
...
然后,您可以在查询中使用它,如下所示:

公共函数findcustomenties():数组
{
返回$this->createQueryBuilder('c')
…您的查询逻辑。。。
->getResult('CustomEntityOr');
}
请注意,您只能为根实体指定要使用的名称或名称。如果获取关联的实体,最终可能会出现更复杂的设置,难以调试

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

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

/**
*@ORM\Entity()
*/
类自定义实体
{
/**
*@ORM\Id()
*@ORM\Column(type=“string”,length=64)
*/
私有字符串$id;
/**
*@ORM\Column(type=“int”)
*/
私人地点;
/**
*@ORM\Column(type=“bool,nullable=true)
*/
私人bool$状态;
私有函数构造(Uuid$id,Location$Location,Status$Status)
{
$this->id=(字符串)$id;
$this->location=$location->getValue();
$this->status=$status->get();
}
公共静态功能新建(位置$Location,状态$Status):self
{
返回新的self(Uuid::v4(),$location,$status);
}
公共函数getId():Uuid
{
返回Uuid::fromString($this->id);
}
公共函数getLocation():位置
{
返回新位置($this->Location);
}
公共函数activate():void
{
$this->status=true;
}
公共函数deactivate():void
{
$this->status=false;
}
公共函数isActive():bool
{
$this->status===true;
}
公共函数isInactive():bool
{
$this->status===false;
}
公用函数未初始化():bool
{
$this->status==null;
}
公共函数getStatus():状态
{
如果($this->status==null){
返回新的NullStatus();
}
如果($this->status==true){
返回新的ActiveStatus();
}
返回新的不活动状态();
}
}
如您所见,您可以使用公共构造函数替换
new()
。它的工作原理与setter类似。我有时甚至使用(private)构造函数中的设置器。在状态的情况下,如果您改为使用多个在内部设置值的方法,则甚至不需要设置器。类似地,在某些情况下,您可能希望返回标量值而不是VO(或者以另一种方式返回,如状态getter和isser所示)

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


您可能还想考虑对实体中的每一个属性都没有VO。虽然它肯定是有帮助的,例如,将电子邮件封装到自定义VO中以确保有效性而不是仅对字符串进行类型提示,但对于一般性(如用户)的东西,它可能不太有用。名称,它应该非常宽容地使用它所接受的字符串,因为有各种各样的名称。使用上面的方法,您可以很容易地在以后引入VO,方法是为VO添加一个新的getter,更改

new()
或任何其他方法,这些方法可以改变您的属性,然后不必更改下面数据模型中的任何内容(除非对值的表示方式有更大的改变)。

Thx。回答很好,我希望其他人也能读到这篇文章。我认为关于VO ID和VO集合的ORM Github原则引起了很多关注。在我看来,ORM原则