【问题标题】:Doctrine with one field of the composite primary key to be auto generated自动生成复合主键的一个字段的学说
【发布时间】:2015-06-04 01:33:24
【问题描述】:

我目前有一个表,它的主键是由 id + 外键组成的复合值。 id 是自动递增的,外键引用另一个表。

在我保存数据的那一刻,我只知道外键值,我希望 id 从数据库返回给我作为一个自动递增的数字。

我知道,Doctrine 不支持为复合主键自动生成 id,所以可以做些什么来允许 Doctrine 保存数据并仍然在部分复合键上自动递增。

注意,在提交这个问题之前,我已经研究了其他几个问题,例如:Defining Composite Key with Auto Increment in MySQLDoctrine: authorize NULL in a foreign composite key,我还多次阅读 Doctrine 的文档,看看我是否遗漏了一些东西 http://doctrine-orm.readthedocs.org/en/latest/tutorials/composite-primary-keys.html#use-case-1-dynamic-attributes

主要问题是关于Doctrine

Every entity with a composite key cannot use an id generator other than
“ASSIGNED”. That means the ID fields have to have their values set before
you call EntityManager#persist($entity).

为了帮助解决这个问题,这里有一个表格是如何构造的示例:

create table composite_example (
    id int(11) not null auto_increment,
    fk_id int(11) not null,
    a_prop varchar(20),
    primary key (id, fk_id)
) engine=InnoDB default charset=utf8;

如果我必须手动构造一个 MySQL 查询以在知道 fk_id 和 a_prop 的值的情况下插入到该表中,我可以这样做:

insert into composite_example (fk_id, a_prop) values (999, 'a_value');

它会在表格上创建一个具有适当 id 值的行。

我怎样才能对 Doctrine 做同样的行为?有谁知道完成工作的任何方法或解决方法?

【问题讨论】:

  • 为什么需要复合键?你为什么不把“id”作为主键呢?
  • 我不能真正给你详细信息,但让我给你一个使用复合键的场景。在任何给定的商店中,您都有 POS,并且每个商店都有一个数据库,其中 POS 1 中的客户 1 和 POS 2 中的客户 1。您不能肯定 POS 1 中的客户 1 与客户 1 中的同一个人POS 2 所以,如果你需要让这 2 个 POS 保持同步,你会怎么做?一个解决方案是使用复合键。
  • 解决方案是将自动生成的字段移动到单独的表中,然后将其与 OneToOne 关系加入。

标签: php mysql symfony doctrine-orm doctrine


【解决方案1】:

这个问题没有简单的解决方案,但这里有一些选择:

1) 您可以删除复合键并使用 UUID 作为键。这不是一个简单的解决方案,因为它会影响您需要更改多少代码、执行迁移需要多长时间以及它如何影响性能。

2) 另一种选择是 Doctrine 社区建议的,也可以在其他 ORM 中使用:您使用排序器。对于此解决方案,您需要创建一个用于存储实体标识符的表,并且下一列将是该标识符的最后一个值。

例子:

Table sequencer
id | entity_name | entity_id
88 | customers   | 77

实体模型需要通知 id 已生成,并且在 pre-persist 上,它需要为该 id 分配一个值,该值来自该表中的 entity_id + 1

select max(entity_id)+1 from sequencer where entity_name = 'customers';

这将导致运行 2 个额外的查询,一个在 pre-persist 上,另一个在 post-persist 上,这将使用新值更新 sequencer 表。

有一些策略可以避免排序器表上的并发,因此它始终具有正确的值,其中之一是锁定表 o.0

3) 您可以编写自己的加载器和持久化器,但此时您可能面临与 UUID 实现一样大的变化。

很多 ORM 不支持这一点,如果您面临同样的问题,您可能必须考虑上述之一。

现在,如果您专门使用 Doctrine,我强烈建议您在 IRC 频道寻求帮助。他们为我提供了一些解决此问题的替代方案非常有帮助。

【讨论】:

    猜你喜欢
    • 2022-08-16
    • 2018-12-25
    • 2013-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-19
    • 1970-01-01
    相关资源
    最近更新 更多