簡體   English   中英

如何在 Doctrine2 中使用 EntityManager 檢索具有所有關聯的實體?

[英]How to retrieve an entity with all of its associations using EntityManager in Doctrine2?

我有一個具有多對多和一對多關聯的簡單實體。 我知道用於獲取相關關聯的“連接”,這是針對我的問題的手動解決方案。

如何使用 Doctrine2 中的 EntityManager 獲取具有所有關聯的實體? 例如:

$this->em
     ->getRepository('Entities\Patientprofile')
     ->findOneByuserid('555555557')
     ->fetchAllAssociations();

來自http://doctrine-orm.readthedocs.org/en/latest/reference/dql-doctrine-query-language.html#temporously-change-fetch-mode-in-dql

您可以暫時設置急切獲取模式:

$query = $em->createQuery("SELECT u FROM MyProject\User u");
$query->setFetchMode("MyProject\User", "address", "EAGER");
$query->execute();

如果你想用這種獲取模式動態加載所有關聯,你可以使用Doctrine\\ORM\\Mapping\\ClassMetadataInfogetAssociationMappings()方法,將你的實體名稱作為參數傳遞給ClassMetadataInfo的構造ClassMetadataInfo ,然后迭代返回的數組作為$assoc並調用:

$query->setFetchMode("MyProject\User", $assoc, "EAGER");

文檔:ClassMetadataInfo#getAssociationMappings()

Doctrine2 setFetchMode 不適用於“EAGER”

我還嘗試在查詢中使用setFetchMode “急切地”獲取關聯實體,但以下內容似乎不起作用:

$query->setFetchMode("MyProject\User", "address", "EAGER");

當我跳入文件時, 我發現第三個參數$fetchMode應該是一個 integer 常量在 Doctrine\\ORM\\Mapping:ClassMetadataInfo 中定義。 當傳遞一個字符串時,它將默認為Mapping\\ClassMetadata::FETCH_LAZY因為這個 if 子句

/**
 * Specifies that an association is to be fetched when it is first accessed.
 */
const FETCH_LAZY = 2;

/**
 * Specifies that an association is to be fetched when the owner of the
 * association is fetched.
 */
const FETCH_EAGER = 3;

/**
 * Specifies that an association is to be fetched lazy (on first access) and that
 * commands such as Collection#count, Collection#slice are issued directly against
 * the database if the collection is not yet initialized.
 */
const FETCH_EXTRA_LAZY = 4;

於是設置相應的整數就解決了問題:

$query->setFetchMode("MyProject\User", "address", 3);

或者在頂部聲明類use Doctrine\\ORM\\Mapping\\ClassMetadata然后使用常量:

$query->setFetchMode("MyProject\User", "address", ClassMetadata::FETCH_EAGER);

編輯:

由於這里似乎對如何以正確的方式獲取關聯存在很多混淆,因此我將編輯我的答案並添加一些有關如何使用存儲庫獲取連接的附加信息。

根據 Doctrine 文檔,有兩種類型的連接:

  1. 常規連接:用於限制結果和/或計算聚合值。

  2. 獲取連接:除了常規連接的使用之外:用於獲取相關實體並將它們包含在查詢的水合結果中。

因此,要獲取包含其關聯的實體,您需要“獲取-加入”所有這些關聯以確保它們被急切地加載。

我通常不使用 DQL 查詢來獲取實體和解決我的獲取連接,而是將自定義方法添加到使用查詢構建器的存儲庫中。 與使用 DQL 相比,這更靈活且更具可讀性。 當我們調用createQuery方法時,查詢構建器將創建正確的 DQL 查詢。 您當然可以檢查創建的 DQL 查詢以進行調試。

來自上述問題的Patientprofile實體存儲庫中此類自定義方法的Patientprofile

public function findPatientByIdWithAssociations($id)(
    // create a query builder for patient with alias 'p'
    $qb = $this->createQueryBuilder('p')
               ->where('p.id = :patient_id')
               ->addSelect('pd')
               ->leftJoin('p.documentation', 'pd')
               ->addSelect('pa')
               ->leftJoin('p.address', 'pa')
               ->setParameter('patient_id', $id);

    $query = $queryBuilder->getQuery();
    return $query->getSingleResult();
}

現在,您可以使用自定義存儲庫方法通過 id(例如“555555557”)獲取患者,包括與患者文檔和地址的關聯:

$repository = $this->em->getRepository('Entities\Patientprofile');
$patient = $repository->findPatientByIdWithAssociations('555555557');

確保同時使用addSelectleftJoin來進行leftJoin加載。

Doctrine 2 使用代理類進行延遲加載,因此您實際上不需要在使用對象之前獲取關聯的數據。 由於 Proxy 類繼承自您的關聯類,因此您可以像使用 freetch 關聯類一樣使用代理。

但是,如果你真的需要獲取實際的關聯類,你需要告訴查詢將獲取模式設置為 Doctrine\\ORM\\Mapping\\ClassMetadata::FETCH_EAGER。 如果您正在使用注釋,則可以通過以下方式實現:

例如

/**
 * @ManyToMany(targetEntity="Item", fetch="EAGER")
 */
private $items;

您可以使用 DQL 查詢:

$query = $em->createQuery("SELECT p, f FROM Entities\\Patientprofile p JOIN p.Foo f WHERE p.id = ?1");
$query->setParameter(1, 321);
$patient = $query->getSingleResult();

面臨同樣的問題。 有必要拉出一個元素的所有父級鏈。 $query->setFetchMode(EntityClass, "alias_in_entity", 3) get s only 1 lvl deep, other parent s 只是代理。 這可以通過將實體類獲取模式更改為熱切來解決。 但是,如果由於某種原因(性能等)無法實現,則可以通過“動態”更改實體元數據來實現@wormhit

例子:

$query = $this->entityManager->createQueryBuilder()->select('fields')
            ->from(FormField::class, 'fields');
$metadata = $this->entityManager->getClassMetadata(FormField::class);
$metadata->setAssociationOverride('parent', ['fetch' => \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER]);

return $query->getOneOrNullResult();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM