【问题标题】:Doctrine Results Missing Entity教义结果缺失实体
【发布时间】:2015-03-24 16:47:51
【问题描述】:

我一直在尝试解决这个问题。让我们从基本信息开始,我有一个客户表和一个联系人表。客户表与联系人有 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;

联系人表与 Client 存在多对一关系:

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 从联系人翻转到客户存储库会产生相反的情况,联系人丢失。

我检查了之前的代码,虽然 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
)

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

这是为什么? Sql语句中的列是否过多?我是不是忘记了注释中的某些内容?

【问题讨论】:

    标签: php doctrine-orm


    【解决方案1】:

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

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

    【讨论】:

    • 我不确定“第二”的相关性如何,但“第一”似乎是一个有希望的领先优势。有证据吗?因为官方文档(doctrine-orm.readthedocs.org/en/latest/reference/…)有这样的例子: $query = $em->createQuery("SELECT u, a FROM User u JOIN u.address a WHERE a.city = 'Berlin'");它也在选择多个实体。
    • 没错,但这是连接的一般工作方式。结果将是数组(0 => 数组(联系人字段,客户端字段))而不是您想要的数组(0 => 联系人,1 => 客户)
    【解决方案2】:

    看了一堆堆栈溢出的问题,我得出以下结论:看起来学说是这样处理“Fetch Joins”的。

    大线索来自这里:

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

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

    当 Doctrine 使用 fetch-join 对查询进行水合时,它会返回类 结果数组的根级别上的 FROM 子句。在上一个 示例返回一个 User 实例数组,每个实例的地址 用户被提取并水合到 User#address 变量中。如果你 访问地址Doctrine不需要懒加载关联 与另一个查询。

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2021-05-15
      • 2017-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多