如何在Doctrine2 QueryBuilder上水合多个实体

时间:2013-10-20 22:25:58

标签: php symfony doctrine-orm

我有一个使用Doctrine2的symfony2应用程序,以及一些City,State,Country,Address的实体。

问题在于,如果我这样做:

    $queryBuilder = $this->em->createQueryBuilder();
    $queryBuilder
        ->select(array('country', 'state', 'city', 'address'))
        ->from('CouponiacsMainBundle:Country', 'country')
        ->leftJoin('country.states', 'state', 'WITH', 'state.name=:stateName OR state.shortName=:stateShortName')
        ->leftJoin('state.cities', 'city', 'WITH', 'city.name=:cityName')
        ->leftJoin('city.addresses', 'address', 'WITH', 'address.address=:address AND address.zip=:zip AND address.latitude=:latitude AND address.longitude=:longitude')
        ->where('country.name=:countryName OR country.shortName=:countryShortName')
        ->orderBy('city.name', 'DESC')
        ->setParameters(array(
            'countryName' => $country,
            'countryShortName' => $countryShort,
            'stateName' => $state,
            'stateShortName' => $stateShort,
            'cityName' => $city,
            'address' => $address['address'],
            'zip' => $address['zip'],
            'latitude' => $address['latitude'],
            'longitude' => $address['longitude'],
        ))
        ->setMaxResults(1);

结果集仅包含Country实体,但不包含State实体。我也尝试使用DQL进行相同的查询但没有成功:

$query = $this->em->createQuery('SELECT country, state, city, address
        FROM CouponiacsMainBundle:Country country
        LEFT JOIN country.states state WITH state.name=:stateName OR state.shortName=:stateShortName
        LEFT JOIN state.cities city WITH city.name=:cityName
        LEFT JOIN city.addresses address WITH address.address=:address AND address.zip=:zip AND address.latitude=:latitude AND address.longitude=:longitude
        WHERE country.name=:countryName OR country.shortName=:countryShortName
        ORDER BY city.name DESC
    ')->setParameters(array(
        'countryName' => $country,
        'countryShortName' => $countryShort,
        'stateName' => $state,
        'stateShortName' => $stateShort,
        'cityName' => $city,
        'address' => $address['address'],
        'zip' => $address['zip'],
        'latitude' => $address['latitude'],
        'longitude' => $address['longitude'],
    ));

如果我手动运行生成的SQL,则状态的结果是正常的,但在结果集上没有状态实体。结果是一个带有Country实体的数组,如果我执行getStates(),我就没有状态。

任何建议表示赞赏, 谢谢!

修改: 这是学说映射:

地址实体:

    <?php

namespace Couponiacs\MainBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Symfony\Component\Validator\Constraints as Assert;
use Couponiacs\MainBundle\Entity\Traits\EnabledEntity;

/**
* Address
*
* @ORM\Table(uniqueConstraints={@ORM\UniqueConstraint(name="idx", columns={"city_id", "address", "zip", "latitude", "longitude"})})
* @ORM\Entity(repositoryClass="Couponiacs\MainBundle\Entity\AddressRepository")
*/
class Address
{
    use TimestampableEntity;
    use EnabledEntity;

    /**
    * @var integer
    *
    * @ORM\Column(type="integer")
    * @ORM\Id
    * @ORM\GeneratedValue(strategy="AUTO")
    */
    private $id;

    /**
    * @var string
    *
    * @ORM\Column(type="string", length=190)
    */
    private $address = '';

    /**
    * @var City $city
    *
    * @ORM\ManyToOne(targetEntity="City", inversedBy="addresses", cascade={"all"})
    */
    private $city;

    /**
    * @var string
    *
    * @ORM\Column(type="string", length=16)
    */
    private $zip = '';

    /**
    * @var string
    *
    * @ORM\Column(type="string", length=32)
    */
    private $latitude = '';

    /**
    * @var string
    *
    * @ORM\Column(type="string", length=32)
    */
    private $longitude = '';

    /**
    * @var ArrayCollection $coupons
    *
    * @ORM\ManyToMany(targetEntity="Coupon", mappedBy="addresses", fetch="EXTRA_LAZY", cascade={"all"})
    */
    private $coupons;



    public function __construct()
    {
    $this->coupons = new ArrayCollection();
    }

    /**
    * Get id
    *
    * @return integer 
    */
    public function getId()
    {
    return $this->id;
    }

    /**
    * Set address
    *
    * @param string $address
    * @return Address
    */
    public function setAddress($address)
    {
    $this->address = $address;

    return $this;
    }

    /**
    * Get address
    *
    * @return string 
    */
    public function getAddress()
    {
    return $this->address;
    }

    /**
    * Set zip
    *
    * @param string $zip
    * @return Coupon
    */
    public function setZip($zip)
    {
    $this->zip = $zip;

    return $this;
    }

    /**
    * Get zip
    *
    * @return string 
    */
    public function getZip()
    {
    return $this->zip;
    }

    /**
    * Set latitude
    *
    * @param string $latitude
    * @return Coupon
    */
    public function setLatitude($latitude)
    {
    $this->latitude = $latitude;

    return $this;
    }

    /**
    * Get latitude
    *
    * @return string 
    */
    public function getLatitude()
    {
    return $this->latitude;
    }

    /**
    * Set longitude
    *
    * @param string $longitude
    * @return Coupon
    */
    public function setLongitude($longitude)
    {
    $this->longitude = $longitude;

    return $this;
    }

    /**
    * Get longitude
    *
    * @return string 
    */
    public function getLongitude()
    {
    return $this->longitude;
    }

    /**
    * Set city
    *
    * @param \Couponiacs\MainBundle\Entity\City $city
    * @return Address
    */
    public function setCity(City $city = null)
    {
    $this->city = $city;

    return $this;
    }

    /**
    * Get city
    *
    * @return \Couponiacs\MainBundle\Entity\City 
    */
    public function getCity()
    {
    return $this->city;
    }

    /**
    * Add coupon
    *
    * @param \Couponiacs\MainBundle\Entity\Coupon $coupon
    * @return Address
    */
    public function addCoupon(Coupon $coupon)
    {
    $this->coupons[] = $coupon;

    return $this;
    }

    /**
    * Remove coupon
    *
    * @param \Couponiacs\MainBundle\Entity\Coupon $coupon
    */
    public function removeCoupon(Coupon $coupon)
    {
    $this->coupons->removeElement($coupon);
    }

    /**
    * Get coupons
    *
    * @return \Doctrine\Common\Collections\Collection
    */
    public function getCoupon()
    {
    return $this->coupons;
    }
}

城市实体:

    <?php

namespace Couponiacs\MainBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Symfony\Component\Validator\Constraints as Assert;
use Couponiacs\MainBundle\Entity\Traits\NameEntity;
use Couponiacs\MainBundle\Entity\Traits\EnabledEntity;

/**
* City
*
* @ORM\Table(
*   indexes={
*     @ORM\Index(name="idx_name", columns={"name"})
*   },
*   uniqueConstraints={
*     @ORM\UniqueConstraint(name="idx_state_name", columns={"state_id", "name"})
*   }
* )
* @ORM\Entity(repositoryClass="Couponiacs\MainBundle\Entity\CityRepository")
*/
class City
{
    use TimestampableEntity;
    use NameEntity;
    use EnabledEntity;

    /**
    * @var integer
    *
    * @ORM\Column(type="integer")
    * @ORM\Id
    * @ORM\GeneratedValue(strategy="AUTO")
    */
    private $id;

    /**
    * @var string
    *
    * @Gedmo\Slug(handlers={
    *   @Gedmo\SlugHandler(class="Gedmo\Sluggable\Handler\RelativeSlugHandler", options={
    *     @Gedmo\SlugHandlerOption(name="relationField", value="state"),
    *     @Gedmo\SlugHandlerOption(name="relationSlugField", value="slug")
    *   })
    * }, fields={"name"})
    * @ORM\Column(type="string", length=190, unique=true)
    * @Assert\NotBlank(message="err.constraint.empty_value")
    */
    private $slug;

    /**
    * @var State
    *
    * @ORM\ManyToOne(targetEntity="State", inversedBy="cities", cascade={"all"})
    */
    private $state;

    /**
    * @var ArrayCollection $addresses
    *
    * @ORM\OneToMany(targetEntity="Address", mappedBy="city", fetch="EXTRA_LAZY", cascade={"all"})
    */
    private $addresses;



    public function __construct()
    {
    $this->addresses = new ArrayCollection();
    }

    /**
    * Get id
    *
    * @return integer 
    */
    public function getId()
    {
    return $this->id;
    }

    /**
    * Set slug
    *
    * @param string $slug
    * @return City
    */
    public function setSlug($slug)
    {
    $this->slug = $slug;

    return $this;
    }

    /**
    * Get slug
    *
    * @return string 
    */
    public function getSlug()
    {
    return $this->slug;
    }

    /**
    * Set state
    *
    * @param \Couponiacs\MainBundle\Entity\State $state
    * @return City
    */
    public function setState(State $state = null)
    {
    $this->state = $state;

    return $this;
    }

    /**
    * Get state
    *
    * @return \Couponiacs\MainBundle\Entity\State 
    */
    public function getState()
    {
    return $this->state;
    }

    /**
    * Add address
    *
    * @param \Couponiacs\MainBundle\Entity\Address $address
    * @return City
    */
    public function addAddress(Address $address)
    {
    $this->addresses[] = $address;

    return $this;
    }

    /**
    * Remove address
    *
    * @param \Couponiacs\MainBundle\Entity\Address $address
    */
    public function removeAddress(Address $address)
    {
    $this->addresses->removeElement($address);
    }

    /**
    * Get addresses
    *
    * @return \Doctrine\Common\Collections\Collection 
    */
    public function getAddresses()
    {
    return $this->addresses;
    }
}

州实体:

    <?php

namespace Couponiacs\MainBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Symfony\Component\Validator\Constraints as Assert;
use Couponiacs\MainBundle\Entity\Traits\NameEntity;
use Couponiacs\MainBundle\Entity\Traits\EnabledEntity;

/**
* State
*
* @ORM\Table(uniqueConstraints={@ORM\UniqueConstraint(name="idx_name_country", columns={"name", "country_id"})})
* @ORM\Table(uniqueConstraints={@ORM\UniqueConstraint(name="idx_shortName_country", columns={"shortName", "country_id"})})
* @ORM\Entity(repositoryClass="Couponiacs\MainBundle\Entity\StateRepository")
*/
class State
{
    use TimestampableEntity;
    use NameEntity;
    use EnabledEntity;

    /**
    * @var integer
    *
    * @ORM\Column(type="integer")
    * @ORM\Id
    * @ORM\GeneratedValue(strategy="AUTO")
    */
    private $id;

    /**
    * @var string
    *
    * @ORM\Column(type="string", length=16)
    * @Assert\NotBlank(message="err.constraint.empty_value")
    */
    private $shortName = '';

    /**
    * @var string
    *
    * @Gedmo\Slug(handlers={
    *   @Gedmo\SlugHandler(class="Couponiacs\MainBundle\Entity\Handler\RelativeSlugHandler", options={
    *     @Gedmo\SlugHandlerOption(name="relationField", value="country"),
    *     @Gedmo\SlugHandlerOption(name="relationSlugField", value="slug")
    *   })
    * }, fields={"name"})
    * @ORM\Column(type="string", length=190, unique=true, nullable=true)
    */
    private $slug;

    /**
    * @var Country
    *
    * @ORM\ManyToOne(targetEntity="Country", inversedBy="states", cascade={"all"})
    */
    private $country;

    /**
    * @var ArrayCollection $cities
    *
    * @ORM\OneToMany(targetEntity="City", mappedBy="state", fetch="EXTRA_LAZY", cascade={"all"})
    */
    private $cities;



    public function __construct()
    {
    $this->cities = new ArrayCollection();
    }

    /**
    * Get id
    *
    * @return integer 
    */
    public function getId()
    {
    return $this->id;
    }

    /**
    * Set shortName
    *
    * @param string $shortName
    * @return State
    */
    public function setShortName($shortName)
    {
    $this->shortName = $shortName;

    return $this;
    }

    /**
    * Get shortName
    *
    * @return string
    */
    public function getShortName()
    {
    return $this->shortName;
    }

    /**
    * Set slug
    *
    * @param string $slug
    * @return State
    */
    public function setSlug($slug)
    {
    $this->slug = $slug;

    return $this;
    }

    /**
    * Get slug
    *
    * @return string 
    */
    public function getSlug()
    {
    return $this->slug;
    }

    /**
    * Set country
    *
    * @param \Couponiacs\MainBundle\Entity\Country $country
    * @return State
    */
    public function setCountry(Country $country = null)
    {
    $this->country = $country;

    return $this;
    }

    /**
    * Get country
    *
    * @return \Couponiacs\MainBundle\Entity\Country 
    */
    public function getCountry()
    {
    return $this->country;
    }

    /**
    * Add city
    *
    * @param \Couponiacs\MainBundle\Entity\City $city
    * @return State
    */
    public function addCity(City $city)
    {
    $this->cities[] = $city;

    return $this;
    }

    /**
    * Remove city
    *
    * @param \Couponiacs\MainBundle\Entity\City $city
    */
    public function removeCity(City $city)
    {
    $this->cities->removeElement($city);
    }

    /**
    * Get cities
    *
    * @return \Doctrine\Common\Collections\Collection 
    */
    public function getCities()
    {
    return $this->cities;
    }
}

国家/地区实体:

    <?php

namespace Couponiacs\MainBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Symfony\Component\Validator\Constraints as Assert;
use Couponiacs\MainBundle\Entity\Traits\UniqueNameEntity;
use Couponiacs\MainBundle\Entity\Traits\EnabledEntity;

/**
* Country
*
* @ORM\Table()
* @ORM\Entity(repositoryClass="Couponiacs\MainBundle\Entity\CountryRepository")
*/
class Country
{
    use TimestampableEntity;
    use UniqueNameEntity;
    use EnabledEntity;

    /**
    * @var integer
    *
    * @ORM\Column(type="integer")
    * @ORM\Id
    * @ORM\GeneratedValue(strategy="AUTO")
    */
    private $id;

    /**
    * @var string
    *
    * @ORM\Column(type="string", length=16, unique=true)
    * @Assert\NotBlank(message="err.constraint.empty_value")
    */
    private $shortName = '';

    /**
    * @var string
    *
    * @ORM\Column(type="string", length=64)
    */
    private $formatShort;

    /**
    * @var string
    *
    * @ORM\Column(type="string", length=64)
    */
    private $formatLong;

    /**
    * @var string
    *
    * @Gedmo\Slug(fields={"name"})
    * @ORM\Column(type="string", length=190, unique=true)
    * @Assert\NotBlank(message="err.constraint.empty_value")
    */
    private $slug;

    /**
    * @var ArrayCollection $states
    *
    * @ORM\OneToMany(targetEntity="State", mappedBy="country", fetch="EXTRA_LAZY", cascade={"all"})
    */
    private $states;

    /**
    * @var ArrayCollection $coupons
    *
    * @ORM\OneToMany(targetEntity="Coupon", mappedBy="country", fetch="EXTRA_LAZY", cascade={"all"})
    */
    private $coupons;



    public function __construct()
    {
    $this->states = new ArrayCollection();
    $this->coupons = new ArrayCollection();
    }

    /**
    * Get id
    *
    * @return integer 
    */
    public function getId()
    {
    return $this->id;
    }

    /**
    * Set shortName
    *
    * @param string $shortName
    * @return Country
    */
    public function setShortName($shortName)
    {
    $this->shortName = $shortName;

    return $this;
    }

    /**
    * Get shortName
    *
    * @return string
    */
    public function getShortName()
    {
    return $this->shortName;
    }

    /**
    * Set formatShort
    *
    * @param string $formatShort
    * @return Country
    */
    public function setFormatShort($formatShort)
    {
    $this->formatShort = $formatShort;

    return $this;
    }

    /**
    * Get formatShort
    *
    * @return string
    */
    public function getFormatShort()
    {
    return $this->formatShort;
    }

    /**
    * Set formatLong
    *
    * @param string $formatLong
    * @return Country
    */
    public function setFormatLong($formatLong)
    {
    $this->formatLong = $formatLong;

    return $this;
    }

    /**
    * Get formatLong
    *
    * @return string
    */
    public function getFormatLong()
    {
    return $this->formatLong;
    }

    /**
    * Set slug
    *
    * @param string $slug
    * @return Country
    */
    public function setSlug($slug)
    {
    $this->slug = $slug;

    return $this;
    }

    /**
    * Get slug
    *
    * @return string 
    */
    public function getSlug()
    {
    return $this->slug;
    }

    /**
    * Add state
    *
    * @param \Couponiacs\MainBundle\Entity\State $state
    * @return Country
    */
    public function addState(State $state)
    {
    $this->states[] = $state;

    return $this;
    }

    /**
    * Remove state
    *
    * @param \Couponiacs\MainBundle\Entity\State $state
    */
    public function removeState(State $state)
    {
    $this->states->removeElement($state);
    }

    /**
    * Get states
    *
    * @return \Doctrine\Common\Collections\Collection 
    */
    public function getStates()
    {
    return $this->states;
    }

    /**
    * Add coupon
    *
    * @param \Couponiacs\MainBundle\Entity\Coupon $coupon
    * @return Country
    */
    public function addCoupon(Coupon $coupon)
    {
    $this->coupons[] = $coupon;

    return $this;
    }

    /**
    * Remove coupon
    *
    * @param \Couponiacs\MainBundle\Entity\Coupon $coupon
    */
    public function removeCoupon(Coupon $coupon)
    {
    $this->coupons->removeElement($coupon);
    }

    /**
    * Get coupons
    *
    * @return \Doctrine\Common\Collections\Collection
    */
    public function getCoupons()
    {
    return $this->coupons;
    }
}

1 个答案:

答案 0 :(得分:0)

问题很可能是您在其他查询之前使用其中一些实体。并且Doctrine保留了一些缓存的东西。它取决于关联是完全加载还是仅部分加载。加载新的实体管理器或其他实体管理器应该可以解决问题。