【问题标题】:unidirectional vs bidirectional in one-to-one relationship一对一关系中的单向与双向
【发布时间】:2014-03-06 21:04:33
【问题描述】:

我在阅读 Doctrine docs 时遇到了这些概念并感到困惑。

我有这些表:

用户 -> id、角色、电子邮件、用户名、密码

学生 -> id、user_id、fname、lname

教师 -> id、user_id、fname、designation

user_id 是来自用户表的外键。那么这应该是单向关系还是双向关系?

它们有何不同?

有人可以提供两者的真实示例吗?

Doctrine 文档说here Doctrine 只会检查关联的拥有方是否有变化。这是什么意思?有哪些变化?

【问题讨论】:

  • 这种“用户可以是老师或学生”的场景不是比一般的关系更适合继承的概念吗?教师和学生仍然可以相关,但作为一名教师可以有很多学生。您最好从(可能是抽象的)用户类继承您的学生/教师,因为他们几乎共享所有属性(如name)并且仅在某些方面有所不同。
  • 我不能使用继承,因为我需要查询用户。如果我使用继承,我只能查询子实体。
  • 您仍然可以创建一个 AbstractUser 和一个从它扩展而来的 BaseUser :)

标签: php database symfony doctrine-orm doctrine


【解决方案1】:

通常,您可以随时使用单向或双向关系。您设计代码是因为您将使用它。也就是说,例如,如果您声明单向关系 oneToOne 是因为您只需要在一侧拥有信息。相反,如果您需要从两个实体访问有关另一个实体的信息,则需要声明您的双向关系。例如:

假设你的 User-Teacher 关系是 OneToOne。

案例 1:您需要知道用户是否是教师,并且您还需要知道哪个用户与教师实体相关 => 您使用双向关系。

/** @Entity */
class User
{
    // ...

    /**
     * @OneToOne(targetEntity="Teacher", mappedBy="user")
     */
    private $teacher;

    // ...
}

/** @Entity */
class Teacher
{
    // ...

    /**
     * @OneToOne(targetEntity="User", inversedBy="teacher")
     * @JoinColumn(name="user_id", referencedColumnName="id")
     */
    private $user;

    // ...
}

默认表看起来像:

CREATE TABLE Teacher (
    id INT AUTO_INCREMENT NOT NULL,
    user_id INT DEFAULT NULL,
    PRIMARY KEY(id)
) ENGINE = InnoDB;
CREATE TABLE User (
    id INT AUTO_INCREMENT NOT NULL,
    PRIMARY KEY(id)
) ENGINE = InnoDB;
ALTER TABLE Teacher ADD FOREIGN KEY (user_id) REFERENCES User(id);

案例 2:您需要访问与教师相关的用户,但您永远不需要知道教师用户,因此您只声明了教师方面的一部分。

参考: http://docs.doctrine-project.org/en/2.0.x/reference/association-mapping.html#one-to-one-unidirectional

有一些限制,主要是在 oneToMany 关系中。一般来说,我会建议你使用双向关系。

“Doctrine 文档在这里说,Doctrine 只会检查关联的拥有方是否有变化。这是什么意思?什么样的变化?”

我对此并不完全确定,但我可以告诉您我对此的理解:当您刷新实体中的更改时(在更改实体并执行 $entityManager->flush() 之后),它只会检查关系中主要实体的更改,也就是说,如果您在另一个实体中进行了更改,它将不会检查两个实体,而只会检查关系中的主要实体。因此,您必须将作为“基础”的那一方声明为所有者,而不是相反。例如,在前面的示例中,如果您从教师实体更改用户实体,Doctrine 不会考虑它,因为用户是所有者。

例如:

$teacher->getUser()->setName('john'); //Doctrine won't check for this change
$user->getTeacher()->setStatus('dismissed'); //Doctrine will track this change

正如我告诉你的那样,我没有测试过这种情况,因为我通常会很好地声明我的关系(你的 FK 将定义哪个是所有者方,在这种情况下是用户)。无论如何,进行测试并确认它并不难。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多