【问题标题】:Doctrine: Custom repository to determine UniqueEntity does not work学说:确定 UniqueEntity 的自定义存储库不起作用
【发布时间】:2016-07-31 12:51:06
【问题描述】:

为了解决problem I asked about earlier,我正在尝试创建一个自定义存储库函数,该函数将根据device、name 和colors 约束确定Repair 的实例是否唯一.

这是我对Repair 类的教义注释。请注意device 属性是多对一(一台设备的多次维修),而colors 是多对多。

/**
 * @ORM\Table(name="repair")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\RepairRepository")
 * @UniqueEntity(fields={"name", "device", "colors"}, repositoryMethod="getSimilarRepairs", message="Repair {{ value }} already exists for this name, device and colour combination.")
 */

这是我的RepairRepository.php,其中$criteria['colors']是一个数组。

public function getSimilarRepairs(array $criteria) {
    $builder = $this->createQueryBuilder('r')
        ->where('r.device = :device')
        ->andWhere('r.colors = :colors')
        ->andWhere('r.name = :name')
        ->setParameters(['deviceid'=>$criteria['device'],'colors'=>$criteria['colors'],'name'=>$criteria['name']]);
    return $builder->getQuery();
}

我有三个问题可能可以归结为一个:

  • 编辑:每次更改,无论是否导致重复,我都会收到存在重复实体的消息。
  • 编辑:尽管出现错误消息,但仍会执行名称更改!
  • 补充:我可以创建任意数量的副本,永远不会出现错误消息。

【问题讨论】:

标签: php doctrine-orm symfony


【解决方案1】:

您的问题是颜色关系是多对多。 在 SQL 中,您不能在此关系上查询 '='。

这很复杂,这就是 Doctrine(我们可能)无法独自完成的原因。

构建查询的部分解决方案:

public function getSimilarRepairs(array $criteria) {
    $builder = $this->createQueryBuilder('r')
        ->where('r.device = :device')
        ->andWhere('r.name = :name')->setParameter('name',$criteria['name'])
        ->andWhere('r.colors = :colors')->setParameter('deviceid',$criteria['device']);

    // r matches only if each of your colors exists are related to r :
    $i=0;
    foreach($criteria['colors'] as $color){
        $i++;
        $builder->join('r.colors','c'.$i)->andWhere('c = :color'.$i)->setParameter('color'.$i,$color);
    }

    // Then you had also to check than there is no other color related to r :

    // I don't know how


    return $builder->getQuery();
}

但让我提出另一个解决方案:

在您的维修实体中,您可以存储相关颜色的副本:

/**
 * @var string
 *
 * @ORM\Column(name="name_canonical", type="string")
 */
private $serializedColors;

用原则生命周期事件设置它:

/** 
* @ORM\PrePersist
* @ORM\PreUpdate 
*/
public function updateColors()
{
    $serializedColors = '';

    foreach($this->colors as $color){
        $serializedColors .= $color->getId().'#';
    }

    $this->serializedColors = $serializedColors;
}

别忘了加@HasLifecycleCallbacks

然后将您的 UniqueEntityConstraint 更改为 fields={"name", "device", "serializedColors"},忘记自定义查询,它会起作用。

【讨论】:

  • 这是一个非常有趣的解决方案@Alsatian。从来没有这样想过。不过,它确实感觉有点“脏”,纯粹为了绕过逻辑而保存数据,但我认为它会提高性能。谢谢你,我会尝试一下,很快就会报告。
  • 是的,它很脏,但我从来没有找到更好的用法。
猜你喜欢
  • 1970-01-01
  • 2013-02-20
  • 1970-01-01
  • 1970-01-01
  • 2012-06-02
  • 2019-02-02
  • 2022-01-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多