我有以下设计问题:我有两个项目都使用doctrine来管理它们的实体。这两个项目都在类似的实体上工作(其中大多数实际上是相同的)。我想现在最好写一个包含两个项目使用的核心实体的库。
但这让我比我最初想的更令人头疼。让我们给出以下示例,我有一个实体
class Entity {
... a lot of managed properties used in both projects
}
然后在项目A中我使用了这个实体,在项目B中我的实体看起来有点不同:
class Entity {
... a lot of managed properties used in both projects
... one managed property only used in project B
}
现在如果我在我的库中声明Entity,我可以在项目B中扩展它以添加其他属性。但问题是如何用学说做到这一点。如果我在库中声明了实体,我就不能轻易地在项目B中将派生类声明为托管类。另一方面,如果我没有声明它在库中管理,我就赢了。能够拥有包含该实体的关联(在我的情况下非常重要,我在所有实体中都有很多关联)。
我该如何应对这种情况?在两个项目中写两次整个实体结构?这对我来说似乎不是正确的事,但我无法想到另一种解决方案。
答案 0 :(得分:1)
这是一个普遍的,实际上非常好的问题。很多人都遇到过这样的问题,我们不能说只有一个正确答案。
我经历过各种解决方案,而我能“使用”的最好方法是复制每个项目中的实体(ies)定义。
为什么?
因为它确实更容易维护,即使您有一些迁移策略(例如使用Doctrine迁移或其他),依赖于特定版本的实体的代码可能会中断。 您可以尝试使用迁移策略工具处理这类问题(我有点不在主题中),然后我建议您在库中存储每个属性(甚至是项目特定的属性)
但是,如果你真的需要它,请这样做。你复制是一件大事吗?有时,将一切都考虑在内并不是一个好主意。
如果复制定义,您还可以只关注您真正关心的属性。这意味着您可以从每个项目的实体定义中省略一些您不关心的属性。
确保您仍然有迁移策略,这总是一个好主意。
答案 1 :(得分:1)
您可以考虑使用包含注释属性集及其相关方法的traits。这将使您有可能拥有一个可以独立构建双方的共同基础。
缺点是两个对象都没有共同的界面,它们的一些内部结构会相同但你无法从外面辨别出来。解决这个问题的方法是编写一个interface
,它公开了在公共库中使用这些实体操作所需的方法。然后,公共trait
可以负责实现该接口。
编辑正如您所指出的,如果我们处理关联,则特征不是很有用,因为您无法覆盖与targetEntity
注释关联的AssociationOverride
。话虽如此,通过搜索该特定主题,我偶然发现ResolveTargetEntityListener
可能是您正在搜索的工具。
官方文档有关于如何使用它的a detailed page(如果您使用Symfony,还有this article)。正如文档中所解释的那样,由于该实用程序,您可以在实体之间建立关系,这些实体基于可在运行时解析的抽象类或接口。
这是一个带有注释MappedSuperClass
的抽象类的工作示例:
的appbundle /型号/ AbstractA.php
use Doctrine\ORM\Mapping as ORM;
/** @ORM\MappedSuperclass */
abstract class AbstractA
{
/**
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(name="text", type="string")
*/
private $text;
/** @ORM\ManyToOne(targetEntity="AppBundle\Model\AbstractB") */
private $b;
}
的appbundle /型号/ AbstractB.php
/** @ORM\MappedSuperclass */
abstract class AbstractB
{
/**
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/** @ORM\Column(name="number", type="integer") */
private $number;
}
的appbundle /实体/ a.php只会
/** @ORM\Entity() */
class A extends AbstractA {}
的appbundle /实体/ B.php
/** @ORM\Entity() */
class B extends AbstractB {}
自从我使用Symfony进行测试后,我不得不在配置中添加以下内容:
doctrine:
orm:
resolve_target_entities:
AppBundle\Model\AbstractA: AppBundle\Entity\A
AppBundle\Model\AbstractB: AppBundle\Entity\B
在询问架构更新的原则时,它会输出:
CREATE TABLE a (id INT AUTO_INCREMENT NOT NULL, b_id INT DEFAULT NULL, text VARCHAR(255) NOT NULL, INDEX IDX_E8B7BE43296BFCB6 (b_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
CREATE TABLE b (id INT AUTO_INCREMENT NOT NULL, number INT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
ALTER TABLE a ADD CONSTRAINT FK_E8B7BE43296BFCB6 FOREIGN KEY (b_id) REFERENCES b (id);