2017-01-11 55 views
1

我在收到一个关联以填充我的Doctrine实体时遇到问题。即使设置为急切加载,实体也会充分填充关联的唯一例外。我有其他类似的协会工作,所以我怀疑有一些基本的理解,我在这里失踪。学说2关联映射总是返回null

我在这里要做的是在对象的实体中填充$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] 
} 

我拥有所有必要的吸气剂s和setter,并且所有必要的数据库数据都存在于两个表中,因此连接列应该没有任何问题。

回答

0

我还没有完全知道什么无法工作的本地查询,但我已经解决了这个PR改变了方向oblem。我发布这个答案的机会很渺茫,以后有人会遇到类似的问题。

我最终所做的是完全取消SHealth存储库,而我只是简单地使用S存储库。我走了这条路线,因为我的本地查询主要是从s中选择。因此,我没有尝试将选择的结果放入sHealth实体(使用本机查询),而是将s加入到实体中,而是从关系的另一端使用更简单的DQL查询。

以下是我的新的存储库中取出的功能,这次在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

/** 
* @ManyToOne(targetEntity="S", inversedBy="health") 
* @JoinColumns({ 
* @JoinColumn(name="l_id", referencedColumnName="l_id"), 
* @JoinColumn(name="s_id", referencedColumnName="id") 
* }) 
*/ 
protected $s; 

故事的寓意是,不是试图使用本机查询为关联执行正确的连接,而是反转实体和左连接(在本例中是通过使用DQL的关联)可能会有所裨益。

0

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

1)标记的关联与一个@Id注释标识符的一部分:

/** 
* @Id 
* @ManyToOne(targetEntity="S") 
* @JoinColumns({ 
* @JoinColumn(name="l_id", referencedColumnName="l_id"), 
* @JoinColumn(name="s_id", referencedColumnName="id") 
* }) 
*/ 
protected $s; 

2)删除另外两列:

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

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

我无法使用单个连接列,因为目标实体的主键是组合键。没有'l_id','id'不是唯一的。 –

+0

@ BrandonJ.Dusseau啊,我明白了,现在我错过了那部分。我会再看一次。 – Wilt

+0

@ BrandonJ.Dusseau我更新了,不知道这是否适用于两个连接列虽然... – Wilt