给定一个实体A
,它通过可选 ManyToOne关系与实体B
和C
相关联 - 这是确保最佳方式的最佳方式一次只使用其中一个关系(XOR)?
我想要实现的目标很好地说明了下面的图像(基数在那里显示不同):
当然,我可以确保引用在存储库代码或其他地方有效,但也许有更多"正确的"使用Doctrine映射功能的方法吗?
A
/**
* @ORM\Table(name="A")
* @ORM\Entity(repositoryClass="Test\AppBundle\Repository\ARepository")
*/
class A
{
/**
* @var
* @ORM\ManyToOne(targetEntity="B", inversedBy="as", cascade={"all"})
*/
private $b = null;
/**
* @var null
* @ORM\ManyToOne(targetEntity="C", inversedBy="as", cascade={"all"}))
*/
private $c = null;
}
乙
/**
* @ORM\Table(name="B")
* @ORM\Entity(repositoryClass="Test\AppBundle\Repository\BRepository")
*/
class B
{
/**
* @var
* @ORM\OneToMany(targetEntity="A", mappedBy="b", cascade={"all"})
*/
private $as = null;
}
C
/**
* @ORM\Table(name="C")
* @ORM\Entity(repositoryClass="Test\AppBundle\Repository\CRepository")
*/
class C
{
/**
* @var
* @ORM\OneToMany(targetEntity="A", mappedBy="c", cascade={"all"})
*/
private $as = null;
}
答案 0 :(得分:1)
我不知道有一个内置的解决方案(并且没有最佳的教义实践),但这里有一些可能对你有帮助的想法:
<强> 1。使用getter / setter方法来&#34; null&#34; $ b关联,如果$ c设置,反之亦然
看起来像这样:
public function setB($b) {
$this->b = $b;
if($b !== null) {
$this->c = null;
}
}
优点是您的实体不可能具有设置$ b和$ c的无效状态。然而,学说使用反射,例如if实体实例是从持久对象创建的,以防止__construct调用。 可能是因为setter方法也有原因所以你的实体进入了一个不需要的状态,但是我不能把我的指控归为一类(可能是为了防止某种脏状态)。
此外,您可以将此视为副作用,对于A
类的用户可能不需要(特别是在您不希望出现这种行为的简单setter方法中)。这是您必须在上下文中详细说明的内容。
这个解决方案可以使用symfony表单。只要属性不公开,表单系统will call the setter methods:
除非财产是公开的,否则它必须有一个&#34; getter&#34;和&#34; setter&#34;方法,以便Form组件可以获取并将数据放到属性上。
<强> 2。使用生命周期回调
我会亲自尝试这种方法,因为我觉得它更容易理解。 (见documentation)
使用prePersist的示例:
/**
* @ORM\PrePersist
* @ORM\PreUpdate
*/
public function checkAssociations()
{
if($this->a !== null && $this->b !== null) {
// throw some error
}
}
此代码
希望有所帮助。
如果有人对symfony中的setter调用有更多信息,那就太棒了。