学说结果缺失实体

Doctrine Results Missing Entity

我已经尝试解决这个问题一段时间了。让我们从基本信息开始,我有一个客户 table 和一个联系人 table。客户端 table 与联系人

具有 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;

联系人 table 与客户有 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

换句话说,缺少客户端实体。将 SELECT FROM 从 Contact 翻转到 Client 存储库产生了相反的情况,contact 丢失了。

我检查了之前的代码,虽然 entityManager 在登录步骤中被重用,但这是第一次访问 Client 和 Contact 存储库,所以我认为这不是缓存问题。

这是正在执行的 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 = ?

作为旁注,如果我更改 select 以便丢失的实体访问特定列,我将获得所需的值。

例如

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

将有以下 array_keys($result):

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

所以我可以向你保证客户端确实存在于数据库中并且应该正确地附加到联系人,只是在第一个 select 语句下我想要整个实体而不只是一个列,实体最终没有被推入结果数组。

这是为什么? Sql 语句中是否有太多列?我是否忘记了注释中的内容?

首先:结果数组中不能有不同的实体:结果中的每一行都必须采用相同的格式。

其次:如果仔细检查 SQL 查询,您会注意到返回的一行同时包含联系人 (c0_) 和客户 (c1_)。 尝试在数据库中执行 SQL 查询以查看结果。

看了一堆堆栈溢出的问题,我得出了以下结论: 看来 doctrine 是这样处理的 "Fetch Joins".

大线索来自这里:

  • Doctrine Regular vs Fetch join

此行为存在的支持证据来自:

  • Doctrine - entities not being fetched
  • Doctrine join bypass lazy loading
  • Doctrine2 query with select on multiple entities from different Symfony2 bundles

更具体地说,这条来自学说文档的引述开始变得有意义 (http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html#joins):

When Doctrine hydrates a query with fetch-join it returns the class in the FROM clause on the root level of the result array. In the previous example an array of User instances is returned and the address of each user is fetched and hydrated into the User#address variable. If you access the address Doctrine does not need to lazy load the association with another query.

通俗地说,在 FETCH JOIN 期间,联系人(如果我从客户端存储库中选择,则为客户端)被指定为根实体。为 Client 找到的任何内容都将被推送到联系人的 $client 变量中,以便之后使用 getter 访问器检索。

检索本身不需要后续数据库查询来获取客户端实体。我需要做一些测试,但看起来这种行为是针对在连接期间返回多个结果的情况。结果没有混乱,而是在一个直观的位置进行了组织。

换句话说,我有错误的期望并且看错了地方。客户实体确实回来了,但没有放在结果中。它是根据联系方式提交的。因此,单独检索它是给定的,但至少不需要另一个数据库调用。

至少现在,我相信我知道为什么当我在 from 字段中有 Client 时,我得到的是 one 特定联系人而不是 all 当我尝试使用 getContact() 访问器时。