实体中的 Doctrine isDeletable 方法

Doctrine isDeletable method in entity

我的数据库中有一个实体(比如成员),它与其他 table 有很多关系(准确地说是 6 个关系)。其中一些我不想用 ORM 映射(我的意思是链接到这个实体),因为它们可能有很多记录(例如 MemberAccessLogs),而其他一些加载许多其他实体。

现在我希望这个成员实体有一个 isDeletable 方法,这样我就可以在管理页面中禁用排除按钮。

如果我在哪里以传统方式执行此操作,我将不得不声明与实体 class 中所有其他 table 的关联,包括 MemberAccessLogs,我会将方法放在这样我就可以测试这些关联是否为空。

但是 AFAIU,我必须对协会的 table 进行提取(或至少计数)以检查是否为空。

另一种方法是获取我想要显示的成员,然后进行单独的查询以检查这些子中是否存在低成本的空成员(select * 来自 table 限制 1) -tables 然后在将它传递给 Twig 之前以编程方式在 Member 中填充 isDeletable 方法。

但我发现这个解决方案很麻烦。谁有更好的方法来做到这一点?

郑重声明:有些人可能认为这是 "premature optimization"。我坚持认为(与某些人相反),您在编程时应该提前考虑,这不是一件坏事。但我真的认为这不是讨论它的地方。请让我们专注于提出的问题好吗? :)

编辑

为了轻松证明 limit 1 比 count 快得多,我在我的数据库 table 中做了一个小测试,该数据库有超过 2000 万行。以下是结果:

select count(*) from loga [20 million+ table]
20678473
1 row(s) fetched - 27023ms

select exists(select null from loga limit 1) 
true
1 row(s) fetched - 2ms

我猜13511,快5倍就够了。 :D

特别懒惰

你可以看看 extra-lazy associations.

基本上,您像往常一样映射所有关联,并添加 fetch="EXTRA_LAZY":

/**
 * @Entity
 */
class CmsGroup
{
    /**
     * @ManyToMany(targetEntity="CmsUser", mappedBy="groups", fetch="EXTRA_LAZY")
     */
    public $users;
}

现在 Doctrine 将 不会complete 集合在第一次访问时加载到内存中,但会执行专门的查询来加载 零件你当时确实需要。

因此,集合上的 $users->count()(或 count($users))将触发一个简单的计数查询,而不是将整个集合加载到内存中。

后加载

您可以使用 postLoad 事件来确定此类实体是否可删除。此 postLoad 事件在 EntityManager 构造实体后调用,因此在加载实体时调用。

给实体添加一个未映射的属性($isDeletable),存储实体是否可以删除。

创建一个 entity listener 来侦听 postLoad 事件。侦听器可以注入 EntityManager、DBAL Connection 或任何其他内容。有了这种依赖,你可以执行任何你想要的查询,并使用结果来设置 $isDeletable.

结果是加载实体时的单个附加查询,之后实体 "knows" 是否可删除。

可以在 Cookbook entry on the Strategy Pattern

中找到使用 postLoad 事件的示例

请注意,当确定是否可删除的条件发生变化时,$isDeletable 的值可能会变得不正确。要解决此问题,您可以跟踪这些情况:

保持跟踪

实体添加一个mapped 属性 ($isDeletable),存储实体是否可以删除。它可能以 true.

开头

当将某些内容添加到关联中意味着实体不再可删除时,将 $isDeletable 设置为 false

当从关联中删除某些内容时,这意味着该实体可再次删除,将 $isDeletable 设置为 true

换句话说:对于每次更改,您都会跟踪实体是否可删除。

这样您就根本不需要任何额外的查询。

有个Cookbook entry on aggregate fields很好地解释了这个概念。