【问题标题】:Symfony Doctrine query builder find entity with many to one relationSymfony Doctrine 查询构建器查找具有多对一关系的实体
【发布时间】:2020-03-19 01:04:17
【问题描述】:

我正在使用 Symfony 为一个项目构建一个网站,该项目的行为类似于“booking.com”网站,但更简单且有一些变化。

数据库字段上的一些错误,但对我的问题并不重要。

如您所见,这些表涉及两个实体:公寓和访问。 客户可以要求参观公寓。这是多对一的关系。

我有一个搜索表单来搜索符合条件的公寓。我只想显示在用户提供的到达和离开日期之间没有任何访问的公寓。 所以我最终在 apartmentRepository 中创建了一个函数来管理这种情况和其他情况。

问题是:我怎样才能得到这些公寓?

这里是这个功能的一个草稿,当然没有完成也不完美(如果你有一些cmet来改进它,那就太好了!)。

public function findByCustom($parameters): ?array
{
   $query =  $this->createQueryBuilder('a');

   foreach ($parameters as $key=> $parameter){
       if($key != 'keywords' and $key!= 'priceMin' & $key!='priceMax' and $key!="typeAp" and $key!="searchVisitDate") $query->orWhere('a.'.$key." = '".$parameter."'");

       if($key == "typeAp")
       {
           $typeApQuery = "";
           foreach ($parameters[$key] as $index => $type)
           {
               if($index !== count($parameters[$key])-1)
               {
                   $typeApQuery.=" a.typeAp = '".$type."' or";
               }
               else
               {
                   $typeApQuery.= " a.typeAp = '".$type."'";
               }
           }
           $query->andWhere($typeApQuery);
       }
   }

   $query->andWhere('a.rentPrice >='.$parameters['priceMin']." and a.rentPrice <= ".$parameters['priceMax']);
   $withoutInner = $query;
   $query
       ->join('App\Entity\Visit', 'v', Join::ON, 'a = v.apartment')
       ->where("v.date between '2020-03-15' and '2020-03-19'");
    $query->getQuery()->getResult();
    $sorted = $withoutInner->andWhere($this->createQueryBuilder('a')->expr()->notIn('a.id', $query));

   return array($sorted);

当然,apartment 有一个访问的集合,并且作为一个名为“apartment”的字段访问,它与公寓对象相关。

我真的没有找到合适的方法来做这件事,我想避免做 SQL,以提高我对 Doctrine 的理解。

感谢您的帮助,因为我现在陷入困境:/

编辑 1:忘了提到我想要在要求的日期之间没有访问或根本没有任何访问的公寓

编辑 2:

public function findByCustom($parameters): ?array
{
   $query =  $this->createQueryBuilder('a');
    $withoutInner = $this->createQueryBuilder("a");

   foreach ($parameters as $key=> $parameter){
       if($key != 'keywords' and $key!= 'priceMin' & $key!='priceMax' and $key!="typeAp" and $key!="searchVisitDate")
       {
           $withoutInner->orWhere('a.'.$key." = '".$parameter."'");
           $query->orWhere('a.'.$key." = '".$parameter."'");
       }


       if($key == "typeAp")
       {
           $typeApQuery = "";
           foreach ($parameters[$key] as $index => $type)
           {
               if($index !== count($parameters[$key])-1)
               {
                   $typeApQuery.=" a.typeAp = '".$type."' or";
               }
               else
               {
                   $typeApQuery.= " a.typeAp = '".$type."'";
               }
           }
           $withoutInner->andWhere($typeApQuery);
           $query->andWhere($typeApQuery);
       }
   }

   $query->andWhere('a.rentPrice >='.$parameters['priceMin']." and a.rentPrice <= ".$parameters['priceMax']);
   $withoutInner->andWhere('a.rentPrice >='.$parameters['priceMin']." and a.rentPrice <= ".$parameters['priceMax']);
   $query
       ->join('App\Entity\Visit', 'v', Join::WITH, 'a.id = v.apartment')
       ->where("v.date between '2020-03-15' and '2020-03-19'");

    $query->getQuery()->getResult();
    $sorted = $withoutInner->andWhere($this->createQueryBuilder('a')->expr()->notIn('a.id', $query));

使用此功能,我得到教义错误:

Error: Method Doctrine\Common\Collections\ArrayCollection::__toString() must not throw an exception, caught ErrorException: Catchable Fatal Error: Object of class Doctrine\ORM\EntityManager could not be converted to string

【问题讨论】:

  • 你加入到访中,选择那些在那个时间段内根本没有访客的公寓。使用日期时间而不是日期时可能会出现问题。同样$query 是一个对象,所以$withoutInner 将在$query 被修改时被修改。改进建议:更短的行。
  • 哦,是的,我没想到这一点。我的意思是不必重新输入该行,但我会这样做。我会尝试一下,如有任何问题会与您联系 :) 如果您可以提供转换为您所说内容的代码,即使我要自己搜索也会很棒 :)

标签: php symfony doctrine symfony4 query-builder


【解决方案1】:

我自己还没有测试过,但是这样的东西应该可以工作:

$query
    ->leftJoin('App\Entity\Visit', 'v', Join::WITH, 'a = v.apartment AND v.date between "2020-03-15" and "2020-03-19"')
    ->where('a.visits IS EMPTY');

这里的想法是使用leftJoin 并仅选择那些在visit 表中没有对应条目的结果。

【讨论】:

  • 谢谢你的回答 :) 我得到的查询(在加入之前添加了一些东西): SELECT a FROM App\Entity\Apartment a LEFT JOIN App\Entity\Visit v ON a = v.apartment AND v.date 不在“2020-03-15”和“2020-03-19”之间,其中 a.typeAp = 'T1' AND(a.rentPrice >=1 和 a.rentPrice [Syntax Error] line 0, col 66: Error: Expected end of string, got 'ON'
  • 可能是WITH 而不是ON(虽然这有点违反直觉)
  • 根据@Jakumi 的评论,阅读this 的答案,WITH 可能是这里的解决方案。
【解决方案2】:

我找到了一个解决方案来获取所有没有租金的公寓(连接为空)。是的,我更改了租金访问,因为这是我主要问题中的一个错误。

 $query->leftJoin('a.rents', 'r',Join::WITH,'a = r.apartment')
        ->where(
            $query->expr()->andX($query->expr()->isNull('r')))
        ->orWhere($query->expr()-> **);

我的公寓实体中有一个属性,其中包含当前公寓的所有租金。所以我用它来连接。使用表达式 isNull 我让它为没有访问的公寓工作。

**:我希望能够获得没有用户输入所需到达日期的位置不在 r.arrival 和 r.departure 之间的公寓。 这将给我所有没有任何租金的公寓和可以免费预订的公寓。

我想过做另一个查询并做一个 notIn 但我也不知道该怎么做。

谢谢。

编辑和解决方案:

我自己发现了如何做到这一点。这绝对不是最好的方法,也不是最好的解决方案,但我的项目没时间了,所以我需要完成这项工作。

$rents = $this->getEntityManager()->createQueryBuilder()
        ->select("a.id")->from('App:Rent', 'r')
        ->andWhere('r.arrival between :arrival and :departure')
        ->leftJoin('r.apartment', 'a')
        ->setParameters(array("arrival"=>\DateTime::createFromFormat('Y-m-d', "2020-04-20")->setTime(00,00,00), "departure"=>\DateTime::createFromFormat('Y-m-d',"2020-04-31")->setTime(00,00,00)))
        ->getQuery()->getArrayResult();


    $rentsSorted = array();
    foreach ($rents as $rent)
    {
        if(!in_array( $rent['id'],$rentsSorted))
        {
            $rentsSorted[] = $rent['id'];
        }
    }
    if(count($rentsSorted)>0)
    {
        $withRentsNotBetweenDates->andWhere('a1.rentPrice >=' . $parameters['priceMin'] . " and a1.rentPrice <= " . $parameters['priceMax'])
            ->andWhere($withRentsNotBetweenDates->expr()->notIn('a1.id', $rentsSorted));
    }
    else
    {
        $withRentsNotBetweenDates->andWhere('a1.rentPrice >=' . $parameters['priceMin'] . " and a1.rentPrice <= " . $parameters['priceMax']);
    }

当然,我会将参数更改为我的表单给出的所需日期。

此代码允许我获取在这些要求日期内存在的所有租金。然后,我将每个公寓 ID 存储在一个数组中,我将传入 not in 以排除这些公寓,因为它们在此期间有租金。

如果您有任何改进或更好的方法来做到这一点,请不要害羞 xD。

祝你有美好的一天。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-05
    相关资源
    最近更新 更多