Коллекция Doctrine2

Хорошо, у меня есть объект User следующим образом

<?php
class User 
{
    /**
     * @var integer
     * @Id
     * @Column(type="integer")
     * @GeneratedValue
     */
    protected $id;
    /**
     * @var \Application\Entity\Url[]
     * @OneToMany(targetEntity="Url", mappedBy="user", cascade={"persist", "remove"})
     */
    protected $urls;
    public function __construct()
    {
        $this->urls = new \Doctrine\Common\Collections\ArrayCollection();
    }
    public function addUrl($url)
    {
       // This is where I have a problem
    }
}

Теперь я хочу проверить, есть ли у пользователя $url в $urls ArrayCollection перед сохранением $url.

Теперь некоторые из примеров, которые я нашел, говорят, что мы должны сделать что-то вроде

if (!$this->getUrls()->contains($url)) {
    // add url
}

но это не работает, так как сравнивает значения элементов. Поскольку $url еще не имеет значения id, это всегда будет давать сбой, и $url будет дублироваться.

Поэтому я был бы очень признателен, если бы кто-нибудь объяснил, как я могу добавить элемент в ArrayCollection, не сохраняя его и избегая дублирования?

Изменить

Мне удалось добиться этого с помощью

$p = function ($key, $element) use ($url) 
{ 
    if ($element->getUrlHash() == $url->getUrlHash()) { 
        return true; 
    } else { 
        return false; 
    } 
};

Но разве это не загружает все URL-адреса, а затем не выполняет проверку? Я не думаю, что это эффективно, поскольку на одного пользователя могут приходиться тысячи URL-адресов.


person Optimus    schedule 29.01.2011    source источник


Ответы (2)


Это пока невозможно "управляемым доменом", т.е. просто используя объекты. Вы должны выполнить запрос для проверки существования:

SELECT count(u.id) FROM User u WHERE ?1 IN u.urls AND u.id = ?2

В Doctrine 2.1 это станет возможным благодаря сочетанию двух новых функций:

  1. Очень ленивые коллекции
  2. @IndexBy для коллекций, поэтому вы должны определить @OneToMany(targetEntity="Url", indexBy="location")
  3. ExtraLazy Collection Поддержка индекса с помощью ->contains().

Пункты 1 и 2 уже реализованы в Doctrine 2 master, а вот 3 пока нет.

person beberlei    schedule 14.02.2011
comment
Итак, вы считаете хорошей идеей создать метод UrlService с addUrl($url, $user), в котором будет использоваться DQL, пока не выйдет доктрина 2.1? Я предполагаю, что использование DQL в объекте невозможно/хорошая идея. - person Optimus; 15.02.2011
comment
или, может быть, UrlService::checkIfExists($url, $user) и запустить DQL в этом методе? - person Optimus; 15.02.2011

Вам следует попробовать использовать exists в коллекции и вручную сравнивать значения.

person Cobby    schedule 31.01.2011
comment
Привет, Кобби, спасибо за ответ. Не могли бы вы дать мне простой пример кода? Я не очень хорошо разбираюсь в замыканиях. - person Optimus; 03.02.2011
comment
Мне удалось добиться этого с помощью `$p = function ($key, $element) use ($url) { if ($element->getUrlHash() == $url->getUrlHash()) { return true; } иначе { вернуть ложь; } };` Но разве это не загружает все URL-адреса, а затем не выполняет проверки? Я не думаю, что это эффективно, поскольку на одного пользователя могут приходиться тысячи URL-адресов. - person Optimus; 15.02.2011