仅使用 FK 动态设置链接 属性 的最佳方法是什么
What is the best way to dynamically set a linked property with just their FK
我有一个具有很多链接属性的实体,当我处理 CSV 导入时,我不想为所有链接字段创建 $em->getReference()
调用(主要是因为我想使其尽可能抽象并且不想对所有可能的引用进行硬编码)。
我更想在给定属性的实体 setter 方法中执行此操作。然而,这将要求我从模型中访问学说,这反过来又是一种不好的做法。
我应该访问实体的元数据并从那里开始,还是有更好的方法,我还没有提到?
在 setter 中执行此操作确实会破坏整个 SOA。如果您关心代码的解耦和抽象,您可以使用 Dependency Inversion.
假设您有实体 A
,它与实体 B
和 C
有关联,然后从原始数据中获取引用以更正 B
和 C
实例你从 CSV
得到,你会定义两个接口,例如:BRepositoryInterface
和 CRepositoryInterface
,它们都可能包含一个方法 find($id)
,但它们仍然必须是不同的。现在让你的各个实体的 Doctrine Repositories 实现这些接口并将它们注入到创建实体 A
.
的服务中
如果你真的想编写一些好的代码,那么你应该创建单独的 类 来实现这些接口中的每一个,然后将你的 Doctrine Repositories 注入其中,这些 类 然后作为这些存储库的包装器,这样你在 DataMapper
层和 business logic
层之间有一个不同的层,它给了你想要的抽象。
这是我最近在研究好的代码、DDD
和设计模式时学到的东西。它远非完美(不是说有这样的东西)。任何 Ideas/Comments 将不胜感激。
更新:关于您的评论:
好的设计所追求的主要目标之一是 "capturing the language of domain experts",(请参阅 this source 第 4 项以了解这些传奇人物的描述)。即:您的代码用简单的英语表达是什么?
您的代码所说的基本上是从与 A
关联的实体的存储库中找到具有这些给定 ID 的对象。这看起来很不错,因为您没有明确依赖于 A
具有关联的内容 to.But 仔细观察,您会发现您确实依赖于实际的 B
和 C
对象及其存储库,因为当您提供 id
对于某些对象,您不仅提供了一个 id
,而且还隐含地说明了该对象是什么,否则 id
除了它是标量之外没有任何意义Value.However 该方法在设计的 语义 和 RAD 中肯定都有用例。但仍然存在 Demeter法则,但可以解决,见下:
无论哪种方式,我认为您绝对应该为 A
对象创建一个看起来像这样的工厂。
class AFactory{
protected $br;
protected $cr;
public function __construct(BRepositoryInterface $br, CrepositoryInterface $cr){
$this->br = $br;
$this->cr = $cr;
}
public function create($atr1, $atr2, $bId, $cId){
$b = $this->br->find($bId);
$c = $this->cr->find($cId);
return new A($atr1, $atr2, $bId, $cId);
}
}
现在您可以通过为该工厂创建另一个工厂来使用您声明的设计实际创建该工厂,这也将解决 得墨忒耳法则 的问题。该工厂将具有Entity Manager
作为依赖项,它将读取 A
的元数据,并根据该元数据获取相关对象的存储库,并从这些存储库创建一个新的 AFactory
实例,现在如果你在实际的 Doctrine Repositories 中实现这些接口(BRepositoryInterface
和 CRepositoryInterface
),AFactory
实例将被成功创建。
我有一个具有很多链接属性的实体,当我处理 CSV 导入时,我不想为所有链接字段创建 $em->getReference()
调用(主要是因为我想使其尽可能抽象并且不想对所有可能的引用进行硬编码)。
我更想在给定属性的实体 setter 方法中执行此操作。然而,这将要求我从模型中访问学说,这反过来又是一种不好的做法。
我应该访问实体的元数据并从那里开始,还是有更好的方法,我还没有提到?
在 setter 中执行此操作确实会破坏整个 SOA。如果您关心代码的解耦和抽象,您可以使用 Dependency Inversion.
假设您有实体 A
,它与实体 B
和 C
有关联,然后从原始数据中获取引用以更正 B
和 C
实例你从 CSV
得到,你会定义两个接口,例如:BRepositoryInterface
和 CRepositoryInterface
,它们都可能包含一个方法 find($id)
,但它们仍然必须是不同的。现在让你的各个实体的 Doctrine Repositories 实现这些接口并将它们注入到创建实体 A
.
的服务中
如果你真的想编写一些好的代码,那么你应该创建单独的 类 来实现这些接口中的每一个,然后将你的 Doctrine Repositories 注入其中,这些 类 然后作为这些存储库的包装器,这样你在 DataMapper
层和 business logic
层之间有一个不同的层,它给了你想要的抽象。
这是我最近在研究好的代码、DDD
和设计模式时学到的东西。它远非完美(不是说有这样的东西)。任何 Ideas/Comments 将不胜感激。
更新:关于您的评论:
好的设计所追求的主要目标之一是 "capturing the language of domain experts",(请参阅 this source 第 4 项以了解这些传奇人物的描述)。即:您的代码用简单的英语表达是什么?
您的代码所说的基本上是从与 A
关联的实体的存储库中找到具有这些给定 ID 的对象。这看起来很不错,因为您没有明确依赖于 A
具有关联的内容 to.But 仔细观察,您会发现您确实依赖于实际的 B
和 C
对象及其存储库,因为当您提供 id
对于某些对象,您不仅提供了一个 id
,而且还隐含地说明了该对象是什么,否则 id
除了它是标量之外没有任何意义Value.However 该方法在设计的 语义 和 RAD 中肯定都有用例。但仍然存在 Demeter法则,但可以解决,见下:
无论哪种方式,我认为您绝对应该为 A
对象创建一个看起来像这样的工厂。
class AFactory{
protected $br;
protected $cr;
public function __construct(BRepositoryInterface $br, CrepositoryInterface $cr){
$this->br = $br;
$this->cr = $cr;
}
public function create($atr1, $atr2, $bId, $cId){
$b = $this->br->find($bId);
$c = $this->cr->find($cId);
return new A($atr1, $atr2, $bId, $cId);
}
}
现在您可以通过为该工厂创建另一个工厂来使用您声明的设计实际创建该工厂,这也将解决 得墨忒耳法则 的问题。该工厂将具有Entity Manager
作为依赖项,它将读取 A
的元数据,并根据该元数据获取相关对象的存储库,并从这些存储库创建一个新的 AFactory
实例,现在如果你在实际的 Doctrine Repositories 中实现这些接口(BRepositoryInterface
和 CRepositoryInterface
),AFactory
实例将被成功创建。