Doctrine 2关联映射始终返回null

时间:2017-01-11 14:28:34

标签: sql doctrine-orm

我遇到了在我的Doctrine实体中填充关联的问题。即使设置为预先加载,实体也会完全填充关联的单个例外。我有其他类似的协会工作,所以我怀疑有一些基本的理解,我在这里失踪。

我在这里要做的是在$s实体中使用S对象填充s,在查询中称为SHealth。我提前为命名道歉,但我不得不删除任何可能识别的内容,因为这是专有代码的一部分。

以下是我的// ------------------------------------------------------------------- // ENTITY FOR SHealth // ------------------------------------------------------------------- /** * Used for tracking the current health of shares. * @Entity(repositoryClass="SHealthRepository") * @Table(name="s_health") */ class SHealth { /** * @Id * @Column(type="integer", name="s_id") */ protected $sId; /** * @Id * @Column(type="integer", name="l_id") */ protected $lId; /** * @Id * @Column(type="smallint", name="s_type") */ protected $sType; /** * @Id * @Column(type="smallint", name="s_subtype") */ protected $sSubtype; /** * @Column(type="smallint", name="health_status") */ protected $healthStatus; /** * @Column(type="datetime", name="update_time") */ protected $updateTime; /** * Scalar value */ protected $active; /** * @ManyToOne(targetEntity="S") * @JoinColumns({ * @JoinColumn(name="l_id", referencedColumnName="l_id"), * @JoinColumn(name="s_id", referencedColumnName="id") * }) */ protected $s; // [Accessors and mutators omitted] } 实体类的大部分内容:

// -------------------------------------------------------------------
// Repository fetch function
// -------------------------------------------------------------------

$rtime_check = !$include_rtimed ? " AND s.rtime IS NULL" : "";
$limit_check = $limit > 0 ? " LIMIT " . $limit : "";

$sql = "SELECT
        s.l_id,
        s.id AS s_id,
        COALESCE(s_health.s_type, s.type) AS s_type,
        COALESCE(s_health.s_subtype, 0) AS s_subtype,
        s_health.health_status,
        s_health.update_time,
        (s.enabled AND
            COALESCE(orsr.status, orsh.status, 0) > 0) AS active
        FROM s

        LEFT JOIN s_health ON
            s.l_id = s_health.l_id AND
            s.id = s_health.s_id AND
            s.type = s_health.s_type AND
            s_health.s_subtype = 0

        LEFT JOIN orsr ON
            s.l_id = orsr.l_id AND
            s.se_id = orsr.se_id AND
            orsr.status IN ([omitted])

        LEFT JOIN orsh ON
            s.l_id = orsh.l_id AND
            s.id = orsh.s_id AND
            orsh.status IN ([omitted])

        WHERE s.l_id IN (:d_ids)
        {$rtime_check}
        GROUP BY s.l_id, s.id
        {$limit_check}";

    // Map the SQL result columns to class properties.
    $rsm = new ResultSetMappingBuilder($this->_em);
    $rsm->addRootEntityFromClassMetadata(SHealth::class, 's_alias');
    $rsm->addScalarResult('active', 'active');

    $query = $this->_em->createNativeQuery($sql, $rsm);
    $query->setParameter("d_ids", $d_ids);

    $results = $query->getResult();

    // Inject aggregate function results into the resulting object.
    $health_objects = [];
    foreach ($results as $result)
    {
        $health_object = $result[0];
        $health_object->setActive($result['active']);
        $health_objects[] = $health_object;
    }

    return $health_objects;

以下是相关存储库类的片段:

S

最后,这是// ------------------------------------------------------------------- // ENTITY FOR S // ------------------------------------------------------------------- /** * @Entity * @Table(name="s") */ class S { /** * @Id * @Column(type="integer") */ protected $id; /** * @Id * @Column(type="integer", name="l_id") */ protected $lId; /** * @Column(type="integer", name="se_id") */ protected $seId; /** * @Column(type="smallint") */ protected $type; /** * @Column(type="boolean") */ protected $enabled; /** * @Column(type="datetime") */ protected $rtime; // [Accessors and mutators omitted] } 类,删除了一些成员:

.NET Command Line Tools (1.0.0-preview2-1-003177)

我拥有所有必需的getter和setter,并且所有必需的数据库数据都存在于两个表中,因此连接列不会出现任何问题。

2 个答案:

答案 0 :(得分:0)

如果您的加入列是实体标识符的一部分,您应该尝试这样一次:

1)使用/** * @Id * @ManyToOne(targetEntity="S") * @JoinColumns({ * @JoinColumn(name="l_id", referencedColumnName="l_id"), * @JoinColumn(name="s_id", referencedColumnName="id") * }) */ protected $s; 注释将关联标记为标识符的一部分:

/**
 * @Id
 * @Column(type="integer", name="s_id")
 */
protected $sId;

/**
 * @Id
 * @Column(type="integer", name="l_id")
 */
protected $lId;

2)删除其他两列:

Email_Body = & PN & " has failed for ap

答案 1 :(得分:0)

我仍然不完全确定是什么阻止了原生查询的工作,但我已经改变了解决这个问题的方向。我发布的答案是,其他人将来会遇到类似的问题。

我最后做的是完全删除"存储库,而只是使用SHealth存储库。我走这条路是因为我的原生查询主要是从S中选择。因此,我没有尝试将select s的结果放入s实体(使用本机查询),而是使用了来自关系另一端的更简单的DQL查询。 / p>

以下是我的新存储库获取功能,这次是在sHealth存储库中,它与问题中的本机查询基本相同:

S

我将此字段添加到我的$query_builder = $this->_em->createQueryBuilder(); $query_builder->select('s, CASE WHEN s.enabled = TRUE AND COALESCE(orsr.status, orsh.status, 0) != 0 THEN TRUE ELSE FALSE END AS active') ->from(S::class, 's') ->leftJoin( ORSR::class, 'orsr', \Doctrine\ORM\Query\Expr\Join::WITH, "s.lId = orsr.lId AND s.seId = orsr.seId AND orsr.status IN ([omitted])" ) ->leftJoin( ORSH::class, 'orsh', \Doctrine\ORM\Query\Expr\Join::WITH, "s.lId = orsh.lId AND s.id = orsh.sId AND orsh.status IN ([omitted])" ) ->where('s.lId IN (:d_ids)') ->setParameter('d_ids', $d_ids); // If rtimed items were not requested, exclude them. if (!$include_rtimed) { $query_builder->andWhere( $query_builder->expr()->isNull('s.rtime') ); } // Apply limit if specified. if (!is_null($limit)) { $query_builder->setMaxResults($limit); } $s_list = $query_builder->getQuery()->getResult(); // Inject aggregate function results into the resulting object. $results = []; foreach ($s_list as $row) { $this_s = $row[0]; $this_s->setActive($row['active']); $results[] = $this_s; } return $results; 实体:

S

而且,我改变了/** * @OneToMany(targetEntity="SHealth", mappedBy="s") * @JoinColumns({ * @JoinColumn(name="l_id", referencedColumnName="l_id"), * @JoinColumn(name="id", referencedColumnName="s_id") * }) */ protected $health; 的关联以反转sHealth中的关联:

S

故事的寓意是,不是试图使用本机查询为关联执行正确的连接,而是反转实体并离开连接(在这种情况下通过使用DQL的关联)而不是。