2017-01-11 75 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