是否可以在每个实体的基础上实施条令2中的自定义水合作用和持久性?
原则2对价值对象(如集合和ID)有一些主要限制。我想知道是否可以使用自定义机制(或实现)将对象属性映射到数据库(加载和持久化)。
我知道有一些可能“解决”这个问题,但我不喜欢其中任何一个:
我知道条令中的生命周期事件可能是有用的。我无法确定postLoad事件是否携带一个已经构造好的实体对象(包含所有VO)?因为那样的话,我就没用了。
向你问好,斯皮甘德罗梅达
是的,您可以在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列时,存在上述问题。当我在