【问题标题】:Can a Discriminator Column be part of the Primary Key in Doctrine2?鉴别器列可以成为 Doctrine2 中主键的一部分吗?
【发布时间】:2011-04-17 12:27:45
【问题描述】:

我在 Doctrine2 中使用 Single Table Inheritance 来存储多个服务的 OAuth 凭据。我想使用服务的 id 作为主键;但是,这并不是所有服务都独一无二的。

我已将数据库设置为使用鉴别器列和服务的 id 作为主键,但我找不到让 Doctrine 使用鉴别器列作为键的方法(除了鉴别器列)。我正在使用 docblock 注释,如果我将鉴别器列添加为 @Id 字段,则会出现错误:

Duplicate definition of column...in a field or discriminator column mapping.

如果我只将该字段定义为鉴别器列,则任何重叠的服务 ID 都会更新所有匹配的行。

除了使用自动生成的 it 值之外,无论如何要让它工作?

【问题讨论】:

    标签: php oop orm single-table-inheritance doctrine-orm


    【解决方案1】:

    不能,描述符列不能用作主键的一部分。

    顺便说一句,为什么您需要 STI 来处理这个用例?你必须为你提供的每个 open-id 服务创建一个新类,听起来很烦人 :-)

    【讨论】:

    • 这还不错,因为各个服务类都提供对服务的访问,它们都只是扩展了一个映射超类来保存公共 OAuth 数据。这样我就可以将$client 与各种服务联系起来。因此,在调用$client 之后调用$client->twitter->user->show($id) 将使用该$client 实体的OAuth 凭据获取Twitter 用户的数据。我敢肯定还有其他/更好的方法可以做到这一点,但目前它运作良好。
    • 我也希望能够将鉴别器用作 PK 的一部分:我有一个表包含各种实体的翻译的用例,我理想的 PK 将是(语言代码、鉴别器, 实体 ID)。同时,在这 3 个字段上使用自动增量 PK + 唯一键即可。
    【解决方案2】:

    对于使用 Hibernate 的用户,您可以(至少从 JPA 2.1 开始)。以下代码完美适用于我的环境(hibernate-entitymanager 4.3.6.Final):

    @Entity
    @Table(name = "CODIFICATIONS")
    @IdClass(CodificationId.class)
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn(name = Codification.DISCRIMINATOR_COLUMN, discriminatorType = DiscriminatorType.INTEGER)
    public abstract class Codification implements Serializable {
    
        public static final String DISCRIMINATOR_COLUMN = "TABLE_ID";
    
        private static final long serialVersionUID = 1L;
    
        @Column(name = "CODIFICATION_ID")
        protected Long codificationId;
    
        @Id
        @Column(name = DISCRIMINATOR_COLUMN, insertable = false, updatable = false)
        protected Long tableId;
    
        @Id
        @Column(name = "CODE_ID", insertable = false, updatable = false)
        protected Long codeId;
    
        @Column(name = "LONG_NAME")
        protected String longName;
    
        @Column(name = "SHORT_NAME")
        protected String shortName;
    
    }
    
    public class CodificationId implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        private Long tableId;
        private Long codeId;
    
        public Long getTableId() {
            return tableId;
        }
    
        public void setTableId(Long tableId) {
            this.tableId = tableId;
        }
    
        public Long getCodeId() {
            return codeId;
        }
    
        public void setCodeId(Long codeId) {
            this.codeId = codeId;
        }
    
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((tableId == null) ? 0 : tableId.hashCode());
            result = prime * result + ((codeId == null) ? 0 : codeId.hashCode());
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            CodificationId other = (CodificationId) obj;
            if (tableId == null) {
                if (other.tableId != null)
                    return false;
            } else if (!tableId.equals(other.tableId))
                return false;
            if (codeId == null) {
                if (other.codeId != null)
                    return false;
            } else if (!codeId.equals(other.codeId))
                return false;
            return true;
        }
    
    }
    
    @Entity
    @DiscriminatorValue(Status.DISCRIMINATOR_VALUE)
    public class Status extends Codification {
    
        public static final String DISCRIMINATOR_VALUE = "2";
    
        private static final long serialVersionUID = 1L;
    
    }
    

    然后我使用以下代码配置与 Status 的关联:

    @ManyToOne
    @JoinColumnsOrFormulas({
            @JoinColumnOrFormula(formula = @JoinFormula(referencedColumnName = Codification.DISCRIMINATOR_COLUMN, value = Status.DISCRIMINATOR_VALUE)),
            @JoinColumnOrFormula(column = @JoinColumn(name = "STATUS", referencedColumnName = "CODE_ID")) })
    private Status status;
    

    【讨论】:

    • 我很确定那不是 PHP。
    • 不,不是,而是“为那些使用 Hibernate 的人准备的”。这个主题不是 PHP 特定的。
    • 嗯,这个问题被标记为 [php] 和 [doctrine-orm],它以 'I'm using Single Table Inheritance in Doctrine2 [...]" 开头,所以我看不出这对面临 OP 问题的人有何帮助。
    • 我只添加了一条评论,因为它还被标记为 [orm] 和 [single-table-inheritance],它们是更通用的标记。我猜,它也可能为 Doctrine 的开发人员指明道路,如果他们曾经寻找解决此问题的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多