实体之间可选的OneToOne关系?

时间:2012-10-28 22:05:07

标签: symfony doctrine-orm

我有一个用户实体。在这种情况下,这被认为是主要实体,仅仅使用它意味着它存在。

User实体具有Store实体。但并非所有用户都必须拥有商店实体。

值得注意的是,这是我们正在使用的现有数据库,User表的id与Store表的id相同。名称(id)和值。只是在某些情况下,Store没有给定用户ID的记录。

用户:

class User extends Entity
{
    /**
    * @ORM\Id
    * @ORM\Column(type="string", length=36)
    */
    protected $id;

    /**
    * @ORM\OneToOne(targetEntity="Store")
    * @ORM\JoinColumn(name="id", referencedColumnName="id")
    */
    protected $store;

    ...
}

商店:

class Store extends Entity
{
    /**
    * @ORM\Id
    * @ORM\Column(type="string", length=36)
    */
    protected $id;

    ...
}

这会导致控制器出现问题。如果用户实体没有商店记录,则会失败并且未找到"实体"例外。这可以使用try catch足够容易处理(我还没有找到一种方法来检查Entity对象是否存在或者只是一个代理)。如果用户确实有商店记录,那么一切都很好。

但我遇到的最大问题尤其是赛程:

protected function createUser($id)
{
    $user = new User();
    $user->setId($id);
    $user->setEmail($id.'@example.com');
    $user->setUserName($id.'_name');
    $user->setArea($this->manager->find('Area', 156)); // Global

    $this->manager->persist($user);

    return $user;
}

当我运行Fixtures时,这会失败。给我错误"完整性约束违规:1048栏' id'不能为空"。如果我从用户中删除商店实体,此消息将消失。简而言之,如果用户没有商店,我就无法添加用户。

任何人都知道发生了什么?我已经做了一些环顾四周,但我无法找到任何内容,包括学说文档,在实体之间建立可选关系。我认为这是一种常见的情况。

2 个答案:

答案 0 :(得分:1)

在此doc页面上找到解决方案:

http://docs.doctrine-project.org/en/latest/tutorials/composite-primary-keys.html#use-case-3-join-table-with-metadata

在我的情况下,用户实体不是使用id字段与Store实体相关联,而是User实体中的store属性将由用户(实体对象)与Store实体相关联。作为回报,Store对象将包含一个User实体,该实体被注释为实体的id。

我确信这就像地狱一样令人困惑,所以请看上面的示例。以下是我调整后的实体类:

用户

class User extends Entity
{
    /**
     * @ORM\Id
     * @ORM\Column(type="string", length=36)
     */
    protected $id;

    /** 
     * @ORM\OneToOne(targetEntity="Store", mappedBy="user") 
     */
    protected $store;

    ...
}

存储

class Store extends Entity
{
    /**
     * @ORM\Column(type="string", length=36)
     */
    protected $id;

    /**
     * @ORM\Id
     * @ORM\OneToOne(targetEntity="User")
     * @ORM\JoinColumn(name="id", referencedColumnName="id")
     */
    protected $user;

    ...
}

现在,如果给定用户没有存储记录,则User实体中的store属性将为null。夹具也按预期运行。

答案 1 :(得分:0)

除了上面的答案,我还需要添加inversedBy属性。否则,将抛出无效的实体映射错误。

使用上面的实体,Store对象需要如下所示:

class Store extends Entity
{
/**
 * @ORM\Column(type="string", length=36)
 */
protected $id;

/**
 * @ORM\Id
 * @ORM\OneToOne(targetEntity="User", inversedBy="store")
 * @ORM\JoinColumn(name="id", referencedColumnName="id")
 */
protected $user;

...
}