Symfony 5:基于父属性值设置属性
在Symfony 5中,假设有3个实体链接如下:Symfony 5:基于父属性值设置属性,symfony,service,repository,entity,Symfony,Service,Repository,Entity,在Symfony 5中,假设有3个实体链接如下: Foo是一个将Bar作为子项的实体Foo作为一个名为fooProperty的属性 Bar将Foo作为父项,将Baz作为子项 Baz当然要将Bar作为父项Baz有一个名为bazProperty的属性 假设bazProperty的值取决于fooProperty的值。我的第一个想法是在baz实体类中引用foo实体: function setBazProperty($value) { if ($this->getBar()->ge
是一个将Foo
作为子项的实体Bar
作为一个名为Foo
的属性fooProperty
将Bar
作为父项,将Foo
作为子项Baz
当然要将Bar作为父项Baz
有一个名为Baz
的属性bazProperty
bazProperty
的值取决于fooProperty
的值。我的第一个想法是在baz
实体类中引用foo
实体:
function setBazProperty($value) {
if ($this->getBar()->getFoo()->getFooProperty > 0) {
$this->bazProperty = $value;
} else {
$this->bazProperty = 0;
}
}
但这会发生在许多sql查询中,因为条令会要求首先获取Bar
实体,然后获取Foo
实体
因此,我设想通过存储库类中管理的唯一查询来访问Foo
实体
但是,由于,我不会将存储库注入Baz
实体,而是使用服务
因此,我创建了一个BazService
,构造函数中有两个参数:
public function __construct(Baz $baz, BazRepository $bazRepository)
{
$this->baz = $baz;
$this->bazRepository= $bazRepository;
}
在这个服务中,我还添加了一个获取Foo
实体的方法:
public function getFoo()
{
return $this->bazRepository->getFoo($this->baz);
}
$bazService = new BazService($baz);
$foo = $bazService->getFoo();
最后,在控制器中,现在我想得到Foo
实体:
public function getFoo()
{
return $this->bazRepository->getFoo($this->baz);
}
$bazService = new BazService($baz);
$foo = $bazService->getFoo();
以下是我的问题:
bazService
):
关注点分离是一个正确的论据。有一些方法可以采用,这在很大程度上取决于如何检索实体。然而,在我看来,一个实体所关心的不是从数据库中获取其他实体的数据,而是存储库或控制器的问题。那么让我们看看如何做到这一点 一种方法是自动检索父实体。根据您的用例,您通常可以这样做(通过
fetch=“EAGER”
-请参见:/),否则您可以实现一个特殊的存储库函数,用于获取其他实体。如果您的实体总是每个实体最多只有一个父实体,这绝对可以将查询数量从3减少到1,因为可以同时检索父实体的父实体和父实体
// in BazRepository
public function getWithParents($id) {
$qb = $this->createQueryBuilder('baz');
$qb->leftJoin('baz.bar', 'bar')
->addSelect('bar')
->leftJoin('bar.foo', 'foo')
->addSelect('foo')
->where('baz.id = :id')
->setParameter('id', $id);
return $qb->getQuery()->getOneOrNullResult();
}
如果子实体访问父实体,它应该只使用缓存中的实体,并避免第二次查询(源:)
如果实体已经“太多”,您可以(再次)创建一个自定义存储库方法,该方法不仅获取Baz实体,还获取Foo.fooProperty值,并将其设置为Baz实体上的虚拟/临时属性,从而稍微作弊
// in BazRepository
public function getWithFooProperty(int $id) {
$qb = $this->createQueryBuilder('baz');
$qb->leftJoin('baz.bar', 'bar')
->lefTJoin('bar.foo', 'foo')
->select('foo.fooProperty as fooProperty')
->where('baz.id = :id')
->setParameter('id', $id);
$result = $qb->getQuery()->getResult(); // should be an array with an array with two keys, but I might be wrong
if(count($result) == 0) {
return null;
}
$baz = $row[0][0];
$baz->fooProperty = $row[0][1];
return $baz;
}
(免责声明:请在此处检查$result,以查看访问是否正确)
您现在可以在Baz中访问它:
function getFooProperty() {
if(isset($this->fooProperty)) {
return $this->fooProperty;
} else {
// fallback, in case entity was fetched by another repository method
return $this->getBar()->getFoo()->getFooProperty();
}
}
关注点分离是一个正确的论据。有一些方法可以采用,这在很大程度上取决于如何检索实体。然而,在我看来,一个实体所关心的不是从数据库中获取其他实体的数据,而是存储库或控制器的问题。那么让我们看看如何做到这一点 一种方法是自动检索父实体。根据您的用例,您通常可以这样做(通过
fetch=“EAGER”
-请参见:/),否则您可以实现一个特殊的存储库函数,用于获取其他实体。如果您的实体总是每个实体最多只有一个父实体,这绝对可以将查询数量从3减少到1,因为可以同时检索父实体的父实体和父实体
// in BazRepository
public function getWithParents($id) {
$qb = $this->createQueryBuilder('baz');
$qb->leftJoin('baz.bar', 'bar')
->addSelect('bar')
->leftJoin('bar.foo', 'foo')
->addSelect('foo')
->where('baz.id = :id')
->setParameter('id', $id);
return $qb->getQuery()->getOneOrNullResult();
}
如果子实体访问父实体,它应该只使用缓存中的实体,并避免第二次查询(源:)
如果实体已经“太多”,您可以(再次)创建一个自定义存储库方法,该方法不仅获取Baz实体,还获取Foo.fooProperty值,并将其设置为Baz实体上的虚拟/临时属性,从而稍微作弊
// in BazRepository
public function getWithFooProperty(int $id) {
$qb = $this->createQueryBuilder('baz');
$qb->leftJoin('baz.bar', 'bar')
->lefTJoin('bar.foo', 'foo')
->select('foo.fooProperty as fooProperty')
->where('baz.id = :id')
->setParameter('id', $id);
$result = $qb->getQuery()->getResult(); // should be an array with an array with two keys, but I might be wrong
if(count($result) == 0) {
return null;
}
$baz = $row[0][0];
$baz->fooProperty = $row[0][1];
return $baz;
}
(免责声明:请在此处检查$result,以查看访问是否正确)
您现在可以在Baz中访问它:
function getFooProperty() {
if(isset($this->fooProperty)) {
return $this->fooProperty;
} else {
// fallback, in case entity was fetched by another repository method
return $this->getBar()->getFoo()->getFooProperty();
}
}
非常固执己见的问题;o/我同意这个问题有点具体,但我在更新依赖于父属性的属性时面临一个真正的问题。我想用最优雅的解决方案来编写一个干净而全面的代码。顺便说一句:如果一个“服务”需要创建一个实体,我会觉得它有点臭。IMHO语法应该是
$bazService->getFoo($baz)
。在你的控制器中,你可以通过控制器方法签名请求一个BazService
,然后通过依赖注入获得它。我同意你的看法。在使用服务时,将实体作为参数传递似乎不是很方便。我还尝试创建一个类bazService
,它扩展了实体baz
。但这在坚持实体性的同时也带来了问题,并没有解决利益分离的问题;o/我同意这个问题有点具体,但我在更新依赖于父属性的属性时面临一个真正的问题。我想用最优雅的解决方案来写一篇cl