Результаты Доктрины Пропавшая Сущность

0

Я пытался понять это сейчас. Начнем с основной информации. У меня есть таблица клиентов и таблица контактов. Таблица клиентов имеет отношение OneToMany и OneToOne с контактом

class Client
{
     /**
     * @var int
     * @Id 
     * @Column(type="integer", nullable=false, unique=true, options={"comment":"Auto incrementing client_id of each client"}) 
     * @GeneratedValue
     */
     protected $pid;

     /**
     * @OneToMany(targetEntity="Contact", mappedBy="client")
     * @JoinColumn(name="contact_id", referencedColumnName="pid")
     * @var Contact[]
     */
     protected $contact;

    /**
     * @OneToOne(targetEntity="Contact")
     * @JoinColumn(name="defaultcontact_id", referencedColumnName="pid", nullable=true)
     * @var Contact
     */
    protected $default_contact;

Таблица контактов имеет отношение ManyToOne к клиенту:

class Contact
{
    /**
     * @var int
     * @Id 
     * @Column(type="integer", nullable=false, unique=true, options={"comment":"Auto incrementing user_id of each user"}) 
     * @GeneratedValue
     */
    protected $pid;

    /**
     * @ManyToOne(targetEntity="Client", inversedBy="contact")
     * @JoinColumn(name="client_id", referencedColumnName="pid")
     */
    protected $client;

Вот запрос, который я использовал:

    $qb = $entityManager->createQueryBuilder();

    $qb->select("cn as contact", "cl as client")
        ->from('DB\Contact', 'cn')
        ->innerJoin('cn.client', 'cl')
        ->where(
            $qb->expr()->andX(
                $qb->expr()->eq('cl.client_name', '?1'),
                $qb->expr()->eq('cn.pid', '?2')
            )
        )
        ->setParameter(1, $client)
        ->setParameter(2, $contact);

    try
    {
        $result = $qb->getQuery()->getOneOrNullResult();
    }

Мне нужен как контакт, так и клиент. И здесь у меня проблемы: array_keys ($ result) заканчивает вывод:

Array
(
    [0] => contact
)

Я хотел что-то вроде этого:

[0] => contact
[1] => client

Другими словами, отсутствует объект Client Entity. Перевернув SELECT FROM из хранилища Contact to Client, появилась обратная ситуация, контакт отсутствовал.

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

Здесь выполняется оператор SQL:

Executing SQL: 
SELECT c0_.pid AS pid0, c0_.caller AS caller1, c0_.address_1 AS address_12, c0_.address_2 AS address_23, 
c0_.unit AS unit4, c0_.city AS city5, c0_.state AS state6, c0_.zip_code AS zip_code7, c0_.phone AS phone8, 
c0_.email AS email9, c0_.is_active AS is_active10, c0_.date_created AS date_created11, 
c0_.date_last_modified AS date_last_modified12, c1_.pid AS pid13, c1_.client_name AS client_name14, 
c1_.is_active AS is_active15, c1_.date_created AS date_created16, c1_.date_last_modified AS date_last_modified17, 
c0_.client_id AS client_id18, c0_.created_by_id AS created_by_id19, c0_.last_modified_by_id AS last_modified_by_id20, 
c1_.defaultcontact_id AS defaultcontact_id21, c1_.created_by_id AS created_by_id22, 
c1_.last_modified_by_id AS last_modified_by_id23 
FROM contacts c0_ 
INNER JOIN clients c1_ ON c0_.client_id = c1_.pid 
WHERE c1_.client_name= ? AND c0_.pid = ?

В качестве побочного элемента, если я изменяю выбор, чтобы отсутствующий объект обращался к определенному столбцу, я получу нужные значения.

например

$qb->select("cn as contact", "cl.pid as client")
   ->from('RGAServ\DB\Contact', 'cn')

будут иметь следующие array_keys ($ result):

Array
(
    [0] => contact
    [1] => client
)

Поэтому я могу заверить вас, что клиент существует в базе данных, и он должен быть надлежащим образом привязан к контакту, а именно, что в первом операторе select, где я хочу весь объект, а не только один столбец, объект не будет нажат в массив результатов.

Почему это? Есть ли слишком много столбцов в инструкции Sql? Я что-то забываю в аннотациях?

Теги:
doctrine2

2 ответа

0
Лучший ответ

Просмотрев кучу проблем с переполнением стека, я пришел к следующему выводу: похоже, что доктрина обрабатывает "Fetch Joins".

Большой ключ приходит отсюда:

Имея подтверждающие доказательства существования этого поведения, исходящие из:

Более конкретно, эта цитата из документации по доктрине начинает иметь смысл (http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html#joins):

Когда Doctrine убирает запрос с помощью fetch-join, он возвращает класс в предложении FROM на корневом уровне массива результатов. В предыдущем примере возвращается массив экземпляров пользователя и адрес каждого пользователя извлекается и гидратируется в переменную адреса пользователя #. Если вы обращаетесь к адресу Doctrine, вам не нужно ленить загружать связь с другим запросом.

В условиях непрофессионала во время FETCH JOIN контакт (или клиент, если я выбрал из репозитория клиента) обозначается как корневой объект. Все, что обнаружено для Клиента, будет затем перенесено в клиентскую переменную контакта $, которую впоследствии будут извлекать с использованием аксессуар-геттера.

Само извлечение не потребует последующего запроса базы данных для извлечения объекта клиента. Мне нужно сделать небольшое тестирование, но похоже, что это поведение было для ситуации, когда во время соединения было получено несколько результатов. Вместо того, чтобы загромождать результаты, они организованы в интуитивном месте.

Другими словами, у меня были неправильные ожидания и я искал не то место. Клиентский объект действительно вернулся, но он не был помещен в результаты. Он был подан в контакт. Поэтому получение его отдельно является заданным, но, по крайней мере, ему не потребуется другой вызов базы данных.

По крайней мере сейчас, я думаю, я знаю, почему, когда у меня был клиент в поле, у меня был один конкретный контакт, а не все, когда я пытался использовать getContact() accessor.

0

Во-первых: вы не можете иметь разные сущности в результирующем массиве: каждая строка в результате должна быть в том же формате.

Во-вторых: если вы внимательно изучите свой SQL-запрос, вы заметите, что одна строка, которая возвращается, содержит как контакт (c0_), так и клиент (c1_). Попробуйте выполнить SQL-запрос в базе данных, чтобы увидеть результат.

  • 0
    Я не уверен, насколько «второе» имеет значение, но «первое» кажется многообещающим. Есть ли доказательства? Поскольку официальная документация ( doctrine-orm.readthedocs.org/en/latest/reference/… ) имеет это в качестве примера: $ query = $ em-> createQuery ("SELECT u, FROM User u ПРИСОЕДИНЯЙТЕСЬ к u.адрес WHERE" a.city = 'Berlin' "); Он также выбирает несколько объектов.
  • 0
    Верно, но это общее, как соединения работают. Результатом будет массив (0 => массив (поля контакта, поля клиента)) вместо желаемого массива (0 => контакт, 1 => клиент)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню