Присоединиться к доктрине Symfony2

Итак, у меня есть вопрос, который я исследовал и исследовал, как заставить это работать, и для жизни я не могу! ... возможно, я просто делаю это неправильно, и я нашел минимальную информацию.

У меня есть таблица с именем timeclock setup..., в которой есть поле: noteBy_id, которое является идентификатором пользователя, которому принадлежит запись...

Что мне нужно сделать сейчас, так это управленческая сторона вещей в системе. Я ожидаю, что более 1 компании будут использовать эту систему часов, и поэтому мне нужно отфильтровать результаты на основе идентификатора компании. В пользовательской таблице , у меня есть поле с именем parentcompany_id

Итак, давайте посмотрим, смогу ли я выразить словами то, что мне нужно сделать.

Мне нужно выбрать * из timeclock и оставить соединение user.parentcompany_id, где timeclock.daydate ‹ :start и где u.parentcompany = :pid

где начало: `date('Y-m-d 00:00:00');

Я настроил этот запрос:

$em = $this->getDoctrine()->getEntityManager();
$start = date('Y-m-d 00:00:00');
$qb = $em->getRepository('EcsCrmBundle:TimeClock');
$qb = $qb->createQueryBuilder('t');

$query = $qb->select('t, u.parentcompany_id')
->from('timeclock', 't')
->leftJoin('Ecs\AgentManagerBundle\Entity\User', 'u', 'ON' 'u.id = t.noteBy_id AND u.parentcompany_id = :pid')
->where('t.daydate < :start')
->andWhere("t.noteBy_id != ''")
->setParameter('start', $start)
->setParameter('pid', $user->getParentcompany())
->getQuery();

$entities = $query->getArrayResult();

Я смотрел и смотрел и не могу найти решение ошибки, которую я получаю:

An exception has been thrown during the rendering of a template ("[Semantical Error] line 0, col 112 near 'u ON u.id = t.noteBy_id': Error: Identification Variable Ecs\AgentManagerBundle\Entity\User used in join path expression but was not defined before.") in EcsCrmBundle:TimeClock:manager.html.twig at line 5.

и запрос, который получает вывод:

SELECT t, u.parentcompany_id FROM Ecs\CrmBundle\Entity\TimeClock t LEFT JOIN Ecs\AgentManagerBundle\Entity\User u ON u.id = t.noteBy_id AND u.parentcompany_id = :pid, timeclock t LEFT JOIN Ecs\AgentManagerBundle\Entity\User u ON u.id = t.noteBy_id AND u.parentcompany_id = :pid WHERE t.daydate < :start AND t.noteBy_id != ''

который при нормальных обстоятельствах работал бы идеально... но в данном случае он просто не работает... Есть идеи?


person Johnny    schedule 04.04.2012    source источник
comment
Я только что заметил, что приведенный выше код дает мне 2 LEFT JOINS вместо 1... Итак, кто знает, где реальная проблема...   -  person Johnny    schedule 05.04.2012
comment
с помощью: stackoverflow.com/questions/9399355/ Я исправил это.....   -  person Johnny    schedule 05.04.2012


Ответы (2)


Недавно мне пришлось сделать это так. Я предполагаю, что ваш noteBy - это ManyToOne в пользовательской таблице, и вы хотите, чтобы он отфильтровал результаты компанией администратора, который в настоящее время вошел в ваш система..

Таким образом, адаптировать соединение, которое мне пришлось написать самому, для такой задачи достаточно просто. Мне лично нравится использовать QueryBuilder, так что это будет сделано в построителе запросов.

Ваша первая ошибка в запросе — строка ->from('timeclock', 't'). Поскольку вы ранее создали свой объект с помощью $qb = $em->getRepository('EcsCrmBundle:TimeClock'); $qb = $qb->createQueryBuilder('t');, вам не нужен from в построителе запросов, так как он будет сгенерирован для вас.

Следующая проблема — это leftJoin, и я объясню почему, когда покажу вам рабочую версию.

И последняя проблема, не позволяющая этому работать так, как вы этого хотите, - это отсутствующее предложение andWhere. Итак, давайте посмотрим на рабочий запрос.

$query = $qb->select('t, u')
     ->leftJoin('t.noteBy', 'u', 'WITH', 'u.id = t.noteBy')
     ->where('t.daydate < :start')
     ->andWhere('u.parentcompany = :pid')
     ->setParameter('start', $start)
     ->setParameter('pid', $user->getParentcompany()) 
     ->getQuery();

Так как мы уже создали объект с помощью $qb = $qb->createQueryBuilder('t'), мы просто выбираем t и u

Для объединения мы присоединяемся к таблице timeclock по столбцу noteBy, который является идентификатором пользователя из пользовательской таблицы. Итак, первым аргументом является псевдоним «от». Итак, поскольку мы присвоили таблице timeclock псевдоним t, мы используем t.noteBy. Следующий аргумент в левом соединении — это псевдоним 2-й таблицы, который в данном случае u, но может быть любым. Третий аргумент для левого соединения в любом случае — это то, как вы к нему присоединяетесь. Здесь будет работать либо WITH, либо ON . и 4-й аргумент - это совпадение, которое вы хотите иметь.. в этом случае u.id must equal t.noteBy

Вы увидите, что я избавился от одного из andWhere, я сделал это, потому что с правильно структурированным запросом он вам не нужен. Однако я добавил andWhere для u.parentcompany, так как это, в конце концов, то, что вы хотите отфильтровать, вы должны иметь его в WHERE, а не как совпадение в самом соединении.

Документация в этом очень ограничена, и мне потребовалось некоторое время, чтобы во всем этом разобраться. Вы, несомненно, как и я, пришли к использованию доктрины, написав свои запросы вручную. И так как вы, кажется, только начинаете с Symfony (я сам тоже примерно через 2 месяца), вы все еще находитесь в мышлении ручного кодирования. Но со временем вы начнете понимать образ жизни DQL. Попробуйте выполнить этот запрос и посмотрите, что произойдет.

person Justin    schedule 05.04.2012

Хорошо, сначала вам нужно связать сущность Timeclock с Company. Всякий раз, когда вы хотите соединить две сущности в Doctrine, они должны быть связаны каким-либо атрибутом (то есть столбцом таблицы).

Я не вижу необходимости в объекте User в этом запросе, поскольку вся информация доступна через объект Company, и вы не фильтруете результаты на основе каких-либо свойств пользователя.

Желаемый запрос должен выглядеть примерно так (более или менее). Я взял на себя смелость и исключил суффиксы _id из атрибутов сущностей, поскольку они имеют тенденцию затуманивать то, что происходит на самом деле. ;)

$query = $this->getEntityManager()->createQuery("SELECT t, c.id FROM EcsCrmBundle:TimeClock t JOIN t.company c WHERE c.id = :pid AND t.daydate < :start AND t.noteBy != ''");

$query->setParameter('start', $start);
$query->setParameter('pid', $user->getParentcompany());
return $query->getArrayResult();

Кроме того, я сделал inner-join (JOIN), так как я думаю, что не может быть часов без компании, но не стесняйтесь изменить это на LEFT JOIN, если вам это больше подходит.

Это то, чего вы пытались достичь?

person Jovan Perovic    schedule 04.04.2012
comment
Сущность компании находится в другом пакете, как и сущность пользователя. Проблема с вашим решением, во всяком случае для меня, заключается в том, что таблица TimeClock имеет ссылку на идентификатор пользователя, поэтому в таблице пользователей нет родительской компании внутри нее таблица timeclock.. Поэтому я должен использовать таблицу пользователей для фильтрации результатов по текущей компании, вошедшей в систему менеджеров... - person Johnny; 05.04.2012