区分类别的原则映射,其中区分列是唯一性约束的一部分

时间:2018-07-23 06:38:59

标签: php doctrine-orm discriminator

我有一个设计不良的数据库,其中采用了 Entity-Attribute-Value 模式,并且我需要为其配置 Doctrine 2.5

下表说明了用户如何将其属性存储在属性表中。以下是说明的PHP类。

CREATE TABLE users (
    user_id INT UNSIGNED AUTOINCREMENT PRIMARY KEY
);

INSERT INTO users (user_id) VALUES (123);

CREATE TABLE user_properties (
    user_id INT UNSIGNED NOT NULL,
    property_name VAR_CHAR(100) NOT NULL,
    property_value VAR_CHAR(100),
    PRIMARY KEY (user_id, property_name),
    FOREIGN KEY (user_id) REFERENCES users(user_id)
);

INSERT INTO user_properties (user_id, property_name, property_value)
    VALUES
        (123, 'first_name', 'Joey Jo-Jo'),
        (123, 'date_of_birth', '1978-01-01');

我想做的是将这些属性设置为具体的实体,这些实体可以作为用户实体上的单独属性进行访问。

<?php
class User
{
    /**
     * @var \Doctrine\Common\Collections\ArrayCollection|AbstractUserProperies[]
     */
    protected $properties;

    public function getFirstName()
    {
        $firstNameProperty = $this->seekPropertyByType(UserFirstName::class);
        return $firstNameProperty ? $firstNameProperty->getValue() : null;
    }

    public function getDateOfBirth()
    {
        $dobProperty = $this->seekPropertyByType(UserDateOfBirth::class);
        return $dobProperty ? $dobProperty->getValue() : null;
    }

    protected function seekPropertyByType($className)
    {
        foreach ($this->properties as $property) {
            if ($property instanceof $clasaName) {
                return $property
            }
        }

        return null;
    }
}

abstract class AbstractUserProperty
{
    /**
     * @var User
     */
    protect $user;

    protected $value;

    public function getValue()
    {
        return $this->value;
    }
}

class UserFirstName extends AbstractUserProperty
{
    public function setValue()
    {
        $this->value = (string)$value;
    }
}

class UserDateOfBirth extends AbstractUserProperty
{
    public function setValue(\DateTime $dob)
    {
        $this->value = $dob;
    }
}

以下是我使用Doctrine配置此设置的尝试。

<entity name="AbstractUserProperty" table="user_properties" inheritance-type="SINGLE_TABLE">
    <discriminator-column name="property_name" type="string" />
    <discriminator-map>
        <discriminator-mapping value="first_name" class="UserFirstName"/>
        <discriminator-mapping value="date_of_birth" class="UserDateOfBirth"/>
    </discriminator-map>

    <id name="user" type="integer" association-key="true" />
    <id name="property_name" type="string" />

    <many-to-one field="user" target-entity="User" inversed-by="properties">
        <join-columns>
            <join-column name="user_id" referenced-column-name="user_id" />
        </join-columns>
    </many-to-one>
</entity>

<entity name="UserFirstName">
    <field name="value" column="property_value" type="string"/>
</entity>

<entity name="UserDateOfBirth">
    <field name="value" column="property_value" type="datetime"/>
</entity>

<entity name="User">
    <one-to-many field="properties" target-entity="AbstractUserProperty" mapped-by="user" fetch="EAGER">
        <cascade>
            <cascade-persist/>
        </cascade>
    </one-to-many>
</entity>

此配置的问题是,我们将从教义中得到一条错误消息,内容为:

  

字段或鉴别符列映射中实体“ AbstractUserProperty”上“ property_name”列的重复定义。

这是因为property_name<discriminator-column>都描述了<id>。但是,如果我不这样做,那么每个User只能拥有一个属性,而我需要多个属性。

我也无法将<id>移到UserFirstNameUserDateBirth,因为Doctrine会抱怨AbstractUserProperty没有ID,即使它是抽象的。 / p>

我唯一想到的就是更改user_properties表以包含代理主键。

0 个答案:

没有答案