我有一个View
实体代表主页面记录,然后我有一个名为ViewVersion
的关联实体,它存储了实体的多个版本,因为它随着时间的推移而发生变化。 View
实体设置当前"已发布" ViewVersion
字段中的VersionId
。这使得简单的OneToOne关联成为可能。但在某些情况下,我还希望获得与此View
实体相关联的所有版本,例如如果我想允许用户查看旧版本并还原。所以我需要另一个映射,它是OneToMany。第一个viewVersion
将映射到活动的"已发布的"版本,第二个viewVersions
将显示所有版本。
实体定义
/**
* @ORM\Entity
* @ORM\Table(name="view")
* @ORM\Entity(repositoryClass="Gutensite\CmsBundle\Entity\View\ViewRepository")
*/
class View extends Entity\Base {
/**
* @ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", inversedBy="view", cascade={"persist", "remove"}, orphanRemoval=true)
* @ORM\JoinColumn(name="versionId", referencedColumnName="id")
*/
protected $viewVersion;
/**
* @ORM\Column(type="integer", nullable=true)
*/
protected $versionId = NULL;
/**
* @ORM\OneToMany(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", mappedBy="viewAll", cascade={"persist", "remove"}, orphanRemoval=true)
*/
protected $viewVersions;
}
/**
* @ORM\Entity
* @ORM\Table(name="view_version")
* @ORM\Entity(repositoryClass="Gutensite\CmsBundle\Entity\View\ViewVersionRepository")
*/
class ViewVersion extends Entity\Base {
/**
* @ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", mappedBy="viewVersion", cascade={"persist"})
*/
protected $view;
/**
* @ORM\ManyToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", inversedBy="viewVersions")
* @ORM\JoinColumn(name="viewId", referencedColumnName="id")
*/
protected $viewAll;
/**
* The primary view entity that this version belongs to.
* @ORM\Column(type="integer", nullable=true)
*/
protected $viewId;
}
这"工作"但是建议与这样的同一个实体有两个关联吗?或者这是一个非常糟糕的主意?
ViewVersion
实体将在两种情况下引用单个View
实体,但映射的关联需要两个单独的变量,例如View
和ViewAll
。我不完全确定内部如何为关联工作,以及如何使用带有映射的引用变量。
或者,我可以摆脱OneToOne关联,只需设置一个ViewRepository函数即可获得基于versionId的当前发布版本(就像用于处理getVersion()的旧映射实体一样)。这样做会有效,但是内部开销会更多,因为它会产生两个查询......或者Doctrine会非常聪明地对其进行优化,就像使用getVersion()一样。
参考文献: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html http://doctrine-orm.readthedocs.org/en/2.0.x/reference/association-mapping.html#one-to-many-bidirectional
答案 0 :(得分:0)
通常,我发现最好的方法是以不同的方式解决这个问题。
我之前见过的一个常见模式是您使用单个表来保存所有记录,并且具有“活动”标记。
如果您选择活动的查询是这样的:
SELECT * FROM table WHERE active = true ORDER BY updated_at DESC LIMIT 1;
然后启用一个新的变得如此简单:
UPDATE table SET active = 1, updated_at = '<timestamp>' WHERE id = <new id>;
UPDATE table SET active = 0, updated_at = '<timestamp>' WHERE id = <old id>;
一旦第一个查询命中,您的新页面就会处于活动状态,而您的第二个查询将避免任何形式的怪异,因为该行已经不再有效。
如果你有其他模型依赖于一致的ID来引用,那么另一个保持一定理智的路径就是有一个表用于活动条目(整体而不是部分),然后是第二个附加表用于跟踪版本的元数据。
后一种方法可以通过Doctrine的继承系统(http://docs.doctrine-project.org/en/2.0.x/reference/inheritance-mapping.html)很好地处理,它可以让你定义基本的View类,然后对于“ViewRevision”模型,扩展View并添加一个“Revised on”类型时间戳。
答案 1 :(得分:0)
根据@jmather的建议我已经确定这个模型是“好的”,因为我需要一个其他实体可以访问的单个View实体(例如指向单个View的路由URL,即“page”)。
我已将View的OneToOne关系更改为仅单向,因为ViewVersion已经通过其他OneToMany与View返回关联(因此它不需要两条路径)。
这允许我为$ view-&gt; getPublished()保留一个简单的方法,并且看起来更合乎逻辑。
/**
* @ORM\Entity
* @ORM\Table(name="view")
*/
class View extends Entity\Base {
/**
* This is a OneToOne Unidirectional association, just so that we can get the
* current published version easily, based on the publishedId.
* @ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\TestVersion")
* @ORM\JoinColumn(name="publishedId", referencedColumnName="id")
*/
protected $published;
/**
* @ORM\Column(type="integer", nullable=true)
*/
protected $publishedId = NULL;
/**
* This is the regular OneToMany Bi-Directional Association, for all the versions.
* @ORM\OneToMany(targetEntity="\Gutensite\CmsBundle\Entity\View\ViewVersion", mappedBy="view", cascade={"persist", "remove"}, orphanRemoval=true)
*/
protected $versions;
}
/**
* @ORM\Entity
* @ORM\Table(name="view_version")
*/
class ViewVersion extends Entity\Base {
/**
* @ORM\ManyToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\View", inversedBy="versions")
* @ORM\JoinColumn(name="viewId", referencedColumnName="id")
*/
protected $view;
/**
* The primary view entity that this version belongs to.
* @ORM\Column(type="integer", nullable=true)
*/
protected $viewId;
}
但是,我发现只要设置了$ view-&gt; publishedId,由于外键约束(即使它是单向的),视图也无法从数据库中删除。所以我必须在删除之前打破该外键链接。我认为没关系。我在此处发布了有关详细信息:Overlapping Entity Association causing Database Foreign Key Constraint Errors when Removing Entity