【问题标题】:Propel ORM Behavior for defining Parent Child relationships?推动 ORM 行为来定义父子关系?
【发布时间】:2012-08-21 23:20:47
【问题描述】:

我正在使用带有 PropelBundle 的 Symfony2,假设我有以下架构:

<table name="person">
  <column name="id" type="INTEGER" primaryKey="true" autoIncrement="true" required="true"/>
  <column name="name" type="VARCHAR" size="100" required="true"/>
</table>
<table name="person_parent">
  <column name="person_id" type="INTEGER" primaryKey="true" required="true"/>
  <column name="parent_id" type="INTEGER" primaryKey="true" required="true"/>
</table>

考虑一个人可以有很多“父母”,就像父母可以有很多孩子“人”一样。 “person_parent”表中的两列都是“person”表的外键。不像 Book/Author 这样的关系,可以在表“book_author”的模式中设置 isCrossRef="true" 以让 Propel 生成用于直接从作者类获取/设置/添加书籍对象的方法,反之亦然,用于父/子关系无法设置 isCrossRef="true",因此无法直接从“Person”对象获取/设置/添加父 Person 对象。换句话说,这是不可能的:

$person = new Person();
$person->setPersonParents($personCollection);

设置任何给定人员的所有父“Person”对象的方法“setPersonParents()”不可用。但是,对于不引用同一个表(如 author_book)的交叉表,设置 isCrossRef="true" 允许以下操作:

$author = new Author();
$author->setBooks($bookCollection);

考虑到这一点,也不可能在“新人”表单中直接选择人的“父母”...

对于类似朋友的关系,有EqualNestBehavior,它允许:

$person = new Person();
$person->setFriends($personCollection);

但是,这种行为似乎不适用于父/子关系,因为它不关心层次结构(如果尝试获取任何给定“人”的“父”,则可以获取该“人”的所有“子”人”除了它的“父母”......)。这是人们对“朋友喜欢”的关系所期望的行为,其中一个人的朋友也是那个人的朋友。

有没有办法将EqualNestBehavior 用于父/子案例?还是有任何其他 Propel 行为或方法来处理这种关系?

【问题讨论】:

  • 请附上代码和架构示例
  • inheritance怎么样?
  • @thecatontheflat :我修改了问题陈述以使其清楚......
  • @WilliamDURAND :继承似乎不适用,因为作为“父母”的人也可以是另一个人的孩子,因此我无法创建“孩子”类和“父母”类,因为它们两者都可以引用同一行...
  • 你说得对,我现在看到了你的用例。

标签: symfony propel


【解决方案1】:

我不确定EqualNestBehavior,但您可以按以下方式设置您的工作流程。

在您的架构中将 FK 定义为 Person 表:

<table name="person">
    <column name="id" type="INTEGER" primaryKey="true" autoIncrement="true" required="true"/>
    <column name="name" type="VARCHAR" size="100" required="true"/>
</table>
<table name="person_parent">
    <column name="person_id" type="INTEGER" primaryKey="true" required="true"/>
    <column name="parent_id" type="INTEGER" primaryKey="true" required="true"/>
    <foreign-key foreignTable="person" name="p1" onDelete="CASCADE" onUpdate="CASCADE">
        <reference local="person_id" foreign="id"/>
    </foreign-key>
    <foreign-key foreignTable="person" name="p2" onDelete="CASCADE" onUpdate="CASCADE">
        <reference local="parent_id" foreign="id"/>
    </foreign-key>
</table>

之后,当您生成模型时 - 您将获得以下方法:

$person = new Person();
$person->getPersonParentsRelatedByParentId();
$person->setPersonParentsRelatedByParentId($personCollection);

$person->getPersonParentsRelatedByPersonId();
$person->setPersonParentsRelatedByPersonId($personCollection);

Setter 接受 PropelCollection 作为参数。

您只需要考虑这种情况,而不是“获得父母”或“获得孩子”,而是考虑相关元素。

【讨论】:

  • 我知道Propel生成的上述方法。我实际上在其他情况下使用它们。问题是上述方法不允许我直接从“新人员表单”访问父人员对象。我必须嵌入一组“person_parent”表单,然后每个表单都将使用“parent_id”的“model”字段访问 Parent Person 对象。但是 person_id 呢?此外,在我的用例中,我只想通过“PersonstoIds”数据转换器传递一个带有逗号分隔的父人员 ID 列表的文本字段(我正在使用 jQuery 自动完成)。
  • 我尝试在 PersonType 表单中嵌入 PersonParentType 表单,以便能够添加“PersonParentsRelatedByPersonId”对象,但问题是我不知道如何在 PersonParentType 表单中定义“person_id”因为“person_id”还不能用于新的人。仅在 PersonParentType 中为“parent_id”添加一个字段会导致“非空违规”,因为缺少“person_id”。问题是关于如何使用 Symfony2 表单处理多对多自引用关系。有什么想法吗?
  • 您可以尝试在需要person_id 的地方创建新的Person() - 并将其绑定到表单。然后,您还可以将来自表单的传入属性绑定到 Person 对象,而不会丢失现有的 id。
  • 我在控制器中新建了一个Person对象和一个新PersonParent对象,然后通过$person->getPersonParentsRelatedByPersonId()->append($personParent1);然后使用 $form = $this->createForm(new PersonType(), $person) 将它们绑定到表单。但是,PersonParentType 仍然需要一个“person_id”,但在保存到数据库之前它不会被分配,所以它不起作用..你还有其他想法吗?
  • 由于此答案中的问题超出了有关专用 Propel 行为的问题,因此我创建了另一个问题来讨论该问题:stackoverflow.com/questions/12123517/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-29
  • 2013-10-28
  • 2014-10-18
  • 2014-08-21
  • 2021-12-12
相关资源
最近更新 更多