資料庫和Doctrine ORM


對於任何應用程式來說,一個最常見且最具挑戰的任務,就是從資料庫讀取和持久化資料資訊。儘管symfony框架並未整合任何需要使用資料庫的元件,但卻緊密整合了一個名為 Doctrine 的三方類函式庫。 Doctrine的主要目標是提供你一個強而有力的工具,讓資料庫互動更輕鬆、更有彈性。

在本章,你將學習如何在Symfony專案中利用doctrine來提供豐富的資料庫互動。

Doctrine與symfony是完全解耦的,使用與否是可選的。本章講的全部是Doctrine ORM,目的是讓你把物件對應到關聯式資料庫(如 MySQL, PostgreSQL 和 Microsoft SQL)。如果你傾向於使用資料庫的原始查詢,這很簡單,可參考 如何使用Doctrine DBAL 一文的講解。

你也可以使用Doctrine ODM類別函式庫將資料持久化到 MongoDB。參考 DoctrineMongoDBBundle 以了解更多資訊。

簡單例子:一件產品(Product) 

#要了解Doctrine是如何運作的,最簡單的方式就是看一個實際應用。在本節,你需要配置你的資料庫,建立一個 Product 對象,把它持久化到資料庫,再取回它。

設定資料庫 

在真正開始之前,你需要設定你的資料庫連線資訊。依照慣例,這部分資訊通常配置在app/config/parameters.yml 檔案中:

# app/config/parameters.ymlparameters:
    database_host:      localhost
    database_name:      test_project
    database_user:      root
    database_password:  password
 # ...


透過parameters. yml 來定義配置,只是一個慣例。配置Doctrine時,定義在那個檔案中的參數,將被主設定檔引用:

# app/config/config.ymldoctrine:
    dbal:
        driver:   pdo_mysql
        host:     "%database_host%"
        dbname:   "%database_name%"
        user:     "%database_user%"
       password: "%database_password%"
<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services"           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"           xmlns:doctrine="http://symfony.com/schema/dic/doctrine"           xsi:schemaLocation="http://symfony.com/schema/dic/services        http://symfony.com/schema/dic/services/services-1.0.xsd        http://symfony.com/schema/dic/doctrine        http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">     <doctrine:config>
        <doctrine:dbal                driver="pdo_mysql"                host="%database_host%"                dbname="%database_name%"                user="%database_user%"                password="%database_password%" />
    </doctrine:config></container>
// app/config/config.php$configuration->loadFromExtension('doctrine', array(
    'dbal' => array(
        'driver'   => 'pdo_mysql',
        'host'     => '%database_host%',
        'dbname'   => '%database_name%',
        'user'     => '%database_user%',
        'password' => '%database_password%',
    ),));

透過把資料庫資訊分離到一個單獨檔案中,你可以很容易地為每個伺服器保存不同的版本。你也可以在專案外輕鬆儲存資料庫設定(或任何敏感資訊),舉例來說,就和apache中的設定資訊一樣。參考 服務容器外部參數如何設定 以了解更多。

現在Doctrine可以連接你的資料庫了,下面的指令可以自動產生一個空的test_project 資料庫:

$  php bin/console doctrine:database:create

設定資料庫為UTF8

Symfony專案開始後,老練的程式設計師也會犯的一個錯誤是,忘了設定他們的資料庫預設字元集和校對規則(charset and collat​​ion),最終變成latin類型,也就是多數資料庫預設的。他們也許在第一次操作時會記得,但在後面的開發中敲打兩行相關的常用命令之後就完全忘記了:

$  php bin/console doctrine:database:drop --force
$  php bin/console doctrine:database:create

設定UTF8為MySQL的預設字元集簡單到只要在配置檔案(一般是my.cnf檔案)中加幾行程式碼就可以了:

[mysqld]#Version 5.5.3 introduced "utf8mb4", which is recommendedcollation-server     = utf8mb4_general_ci # Replaces utf8_general_cicharacter-set-server = utf8mb4            # Replaces utf8

你也可以改變Doctrine的預設字元集,以便產生的SQL使用設定正確的字元集。

# app/config/config.ymldoctrine:
    dbal:
        charset: utf8mb4
        default_table_options:
            charset: utf8mb4
            collate: utf8mb4_unicode_ci
<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services"           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"           xmlns:doctrine="http://symfony.com/schema/dic/doctrine"           xsi:schemaLocation="http://symfony.com/schema/dic/services        http://symfony.com/schema/dic/services/services-1.0.xsd        http://symfony.com/schema/dic/doctrine        http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">     <doctrine:config>
        <doctrine:dbal                charset="utf8mb4">
            <doctrine:default-table-option name="charset">utf8mb4</doctrine:default-table-option>
            <doctrine:default-table-option name="collate">utf8mb4_unicode_ci</doctrine:default-table-option>
        </doctrine:dbal>
    </doctrine:config></container>
// app/config/config.php$configuration->loadFromExtension('doctrine', array(
    'dbal' => array(
        'charset' => 'utf8mb4',
        'default_table_options' => array(
            'charset' => 'utf8mb4'
            'collate' => 'utf8mb4_unicode_ci'
        )
    ),));

我們推薦避免使用Mysql的 uft8 字元集,因為它並不相容於4-byte unicode字符,如果字串中有這種字元會被清空。不過這種情況被修復了,參考 新型utf8mb4字元集

如果你要用SQLite當資料庫,在path選項中設定你的資料庫路徑:

# app/config/config.ymldoctrine:
    dbal:
        driver: pdo_sqlite
        path: "%kernel.root_dir%/sqlite.db"
        charset: UTF8
<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services"           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"           xmlns:doctrine="http://symfony.com/schema/dic/doctrine"           xsi:schemaLocation="http://symfony.com/schema/dic/services        http://symfony.com/schema/dic/services/services-1.0.xsd        http://symfony.com/schema/dic/doctrine        http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">     <doctrine:config>
        <doctrine:dbal                driver="pdo_sqlite"                path="%kernel.root_dir%/sqlite.db"                charset="UTF-8" />
    </doctrine:config></container>
// app/config/config.php$container->loadFromExtension('doctrine', array(
    'dbal' => array(
        'driver'  => 'pdo_sqlite',
        'path'    => '%kernel.root_dir%/sqlite.db',
        'charset' => 'UTF-8',
    ),));

建立一個Entity類

假設你正在建立一套程序,其中有些產品需要展示。即使不考慮Doctrine或資料庫,你已經知道你需要一個 Product 物件來呈現這些產品。在你AppBundle的Entity 目錄下創建這個類別:

// src/AppBundle/Entity/Product.phpnamespace AppBundle\Entity; class Product{
    private $name;
    private $price;
    private $description;}

這個類別——常被稱為一個“Entity”,表示一個保存著資料的基本類別 ——它很簡單,可以滿足程式中所需產品的業務需求。這個類別還不能被儲存到資料庫中——它只是個簡單的PHP類別。

一旦你學習了Doctrine背後的概念,你可以讓Doctrine為你建立entity類別。它將問你一些互動問題來幫你創造任意的entity:

$  php bin/console doctrine:generate:entity

新增映射資訊 

Doctrine允許你以一種更有趣的方式來使用資料庫,而不只是把標量資料的行(rows)取出到陣列中。 Doctrine允許你從資料庫中取出整個 物件,同時持久化整個物件到資料庫中。對Doctrine來說要實現這些,你必須 映射 資料表到特定的PHP類別中,那些表的列(columns)必須被映射為對應PHP類別的特定屬性。

1466153595_56497_19601_doctrine_image_1.png

你要以「元資料(meatdata)」形式來提供這些映射信息,有一組規則可以準確告之Doctrine Product 類別及其屬性應該如何對應到 一個特定的資料表。這個metadata可以透過不同的格式來指定,包括YAML,XML或透過DocBlock註解(譯註:annotations)直接定義到Product 類別中:

// src/AppBundle/Entity/Product.phpnamespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; /**
 * @ORM\Entity
 * @ORM\Table(name="product")
 */class Product{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;     /**
     * @ORM\Column(type="string", length=100)
     */
    private $name;     /**
     * @ORM\Column(type="decimal", scale=2)
     */
    private $price;     /**
     * @ORM\Column(type="text")
     */
    private $description;
# src/AppBundle/Resources/config/doctrine/Product.orm.ymlAppBundle\Entity\Product:
    type: entity
    table: product
    id:
        id:
            type: integer
            generator: { strategy: AUTO }
    fields:
        name:
            type: string
            length: 100
        price:
            type: decimal
            scale: 2
        description:
            type: text
<!-- src/AppBundle/Resources/config/doctrine/Product.orm.xml --><?xml version="1.0" encoding="UTF-8" ?><doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"                  xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping        http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">     <entity name="AppBundle\Entity\Product" table="product">        <id name="id" type="integer">            <generator strategy="AUTO" />        </id>        <field name="name" type="string" length="100" />        <field name="price" type="decimal" scale="2" />        <field name="description" type="text" />    </entity></doctrine-mapping>

#一個bundle只可以接受一種metadata的定義格式。例如,不能把YAML的metadata定義並加入了註解(annotation)的PHP entity類別混用。

表名是可選的,如果省略,將自動取決於entity類別的名稱。

Doctrine允許你選擇廣泛的欄位類型,每一種都有自己的設定。可用字段類型的信息,參考 Doctrine字段類型參考。

你也可以查看Doctrine官方文件 Basic Mapping Documentation 以了解關於映射的所有細節資訊。如果你使用annotation,你需要為所有annotation加掛 ORM\ (例如  ORM\Column(...) ),這在Doctrine文件中並未寫明。你還需要去包容 use Doctrine\ORM\Mapping as ORM; 聲明,它可以 import(導入) ORM annotation前綴。

小心Entity類別名稱(或其屬性)同時也是一個SQL保留的關鍵字(如groupuser )。例如,如果你的entity類別名稱為 Group ,那麼,預設時,你的表名將會是group,這在一些資料庫引擎中可能會導致SQL錯誤。參考 Reserved SQL keywords documentation 以了解如何正確規避這些名稱。可選地,你可以任意選擇資料庫的schema,輕鬆地對應成不同的表名或列名。參考  Creating Classes for the Database  和 Property Mapping文件。

#

當使用其他一些「使用了annotations」的類別庫或程式(如Doxygen)時,你應該把@IgnoreAnnotation 註解加入類別中,來指示Symfony應該忽略哪個annotation。

例如,要避免@fn annotation拋出例外,新增下列註解:

/**
 * @IgnoreAnnotation("fn")
 */class Product// ...

建立entity之後,你應該使用以下指令來驗證映射(mappings):

$  php bin/console doctrine:schema:validate

產生Getters和Setters 

儘管Doctrine現在知道如何持久化Product 物件到資料庫,但類別本身還不具備真正用途。因為Product 只是一個有private 屬性的常規PHP類,你需要建立public 的getter和setter方法(例如getName() , setName($name) )以便在程式其他部分來存取它的屬性(其屬性是protected)。幸運的是,下面的指令可以自動產生這些模板化的方法:

$  php bin/console doctrine:generate:entities AppBundle/Entity/Product

這個指令可以確保 Product 類別所有的getter和setter都被產生。這是一個安全的命令列-你可以多次執行它,它只會產生那些不存在的getters和setters(即,不會取代現有的方法)。

重要提示下面這句話極為深刻,乃是活用Doctrine的關鍵。大家一定照做。

記得,doctrine entity generator產生的是簡單的getters/setters。你應該複審那些已生成的方法,在必要時,添加邏輯進去,以滿足你的程序之需求。

關於doctrine:generate:entities 的更多內容

使用doctrine:generate:entities 指令你可以:

  • 在entity類別中產生getters和setters;

  • ##在entity類別配置了

    @ORM\ Entity(repositoryClass=”…”) annotation的情況下產生所對應的repository類別;

  • 為1:n 或n:m 產生合適的建構器。

doctrine:generate:entities 指令會儲存原始Product.php 檔案的備份並命名為Product.php~ 。有些時候這個檔案可能會引發「Cannot redeclare class」錯誤。它可以被安全刪除。你也可以使用 –no-backup 選項,來防止產生這些備份檔案。

注意,你並不

需要 (依賴)這個指令。你也可以手寫getters和setters。這個選項的存在只是為了節省你的時間,因為在開發過程中建立這些方法是一個常見任務。

#

你也可以為一個bundle或一個entity命名空間內的所有已知實體(任何包含Doctrine映射資訊的PHP類別)來產生getter和setter:

# generates all entities in the AppBundle# 生成AppBundle下的全部entities$  php bin/console doctrine:generate:entities AppBundle
# generates all entities of bundles in the Acme namespace
# 生成Acme命名空间下的bundles的全部entities
$  php bin/console doctrine:generate:entities Acme

建立資料表/Schema 

現在你有了一個包含映射資訊的可用Product 類,因此Doctrine確切地知道如何持久化它。當然,你還沒有對應的 product 資料表在庫中。幸運的是,Doctrine可以自動建立所有的資料表。要這麼做,執行以下指令:

$  php bin/console doctrine:schema:update --force

說真的,這條指令出奇的強大。它會比較你的資料庫理論上應該是 什麼樣子的(基於你的entities的映射資訊)以及實際上 它應該是什麼樣,然後執行所需的SQl語句來將資料庫的schema 更新到 它該有的樣子。換句話說,如果你新增了一個包含「映射元資料」(mapping metadata)的新屬性到Product 並執行此任務,它將執行所需的"ALTER TABLE" 語句,向已經存在的product 表格新增那個新欄位。

一個利用此功能之優勢的更佳方式是透過migrations,它允許你產生這些SQL語句,並把它們並儲存到migration類別中,這些類別能夠有序地運行在你的生產環境中,進而安全可靠地更新追蹤資料庫的schema改變。

不管你是否利用了資料庫遷移,doctrine:schema:update 指令只適合在開發環境中使用。它不應該被用於生產環境。

現在你的資料庫中有了一個全功能的product表,它的欄位與你指定的元資料相符。

持久化物件到資料庫 

現在你有了一個Product實體和與之映射的product資料庫表。你可以把資料持久化到資料庫裡。在Controller內,它非常簡單。加入下面的方法到bundle的DefaultController。

現在你已經把Product entity 映射到與之對應的product 表中,你已經準備好把Product 物件持久化到資料庫中。在控制器裡面,這極為簡單。向bundle的 DefaultController 添加以下方法:

// src/AppBundle/Controller/DefaultController.php // ...use AppBundle\Entity\Product;use Symfony\Component\HttpFoundation\Response; // ...public function createAction(){
    $product = new Product();
    $product->setName('Keyboard');
    $product->setPrice(19.99);
    $product->setDescription('Ergonomic and stylish!');     $em = $this->getDoctrine()->getManager();     // tells Doctrine you want to (eventually) save the Product (no queries yet)
    // 告诉Doctrine你希望(最终)存储Product对象(还没有语句执行)
    $em->persist($product);     // actually executes the queries (i.e. the INSERT query)
    // 真正执行语句(如,INSERT 查询)
    $em->flush();     return new Response('Saved new product with id '.$product->getId());}

如果你正在跟進本例程,需要建立一個路由,並指向這個action,才能看到它運行。

本範例展示了在控制器中使用Doctrine的 getDoctrine() 方法。這是取出 doctrine 服務的快捷方法。若你在服務中註入此服務,即可在任何地方使用doctrine。參考 服務容器 以了解更多創建服務之內容。

深入分析前面的範例:

  • #10-13行 在此處實例化,並且像其他常規PHP對象一樣去使用$product 物件。
  • 15行 這一行取出了Doctrine的 entity manager 對象,它負責處理資料庫的持久化(譯註:寫入)和取出物件的過程。
  • 18行 persist($product) 調用,告訴Doctrine去 "管理" $product 物件。它 沒有 引發對資料庫的請求。
  • 21行flush() 方法被呼叫時,Doctrine會遍歷它管理的所有物件以決定是否需要被持久化到資料庫。本範例中, $product 物件的資料在庫中並不存在,因此entity manager要執行INSERT 請求,在product 表中建立一個新行。

事實上,由於Doctrine了解你的全部被管理的實體,當你呼叫flush() 方法時,它會計算出所有的變更集合(changeset),並以正確順序執行語句。它利用準備好的快取語句以略微提高效能。例如,你要持久化總數為100的Product 對象,然後呼叫flush() 方法,Doctrine將用一個單一的prepare語法對象,來執行100次INSERT 請求。

如果 flush() 呼叫失敗,一個 Doctrine\ORM\ORMException 例外會被拋出。參考 Transactions and Concurrency(處理和並發)。

#

在建立和更新物件時,工作流程是相同的。在下一小節你將會看到,如果記錄已經存在於資料庫中,Doctrine是如何聰明地自動發出一個 Update 語句的。

Doctrine提供了一個類別庫,讓你可以程式化地載入測試資料到你的專案中(即,"fixture data",固定的資料)。參考 DoctrineFixturesBundle 以了解更多。

從資料庫取得物件 

#從資料庫取回物件就更簡單了,舉個例子,假如你配置了一個路由,基於產品的id 來顯示特定的Product 物件:

public function showAction($productId){
    $product = $this->getDoctrine()
        ->getRepository('AppBundle:Product')
        ->find($productId);     if (!$product) {
        throw $this->createNotFoundException(
            'No product found for id '.$productId
        );
    }     // ... do something, like pass the $product object into a template
    // ... 做一些事,比如把 $product 对象传入模板}

你可以使用@ParamConverter 快捷註釋,毋須編寫任何程式碼即可實現相同的功能。參考 FrameworkExtraBundle 以了解更多。

當你要查詢某個特定類型的物件時,你總是要使用它的」respository」(寶庫)。你可以認為Respository是一個PHP類,它的唯一工作就是幫助你從那個特定的類別中取出entity。對於一個entity類,要存取其寶庫,通過:

$repository = $this->getDoctrine()
    ->getRepository('AppBundle:Product');

appBundle:Product 是快捷寫法,你可以在Doctrine裡隨處使用,以替代entity類的FQCN類名(如 AppBundle\Entity\Product )。只要你的entity存放在bundle的 Entity 命名空間下,它就會運作。

一旦有了Repository對象,你就可以存取它的全部有用的方法了。

$repository = $this->getDoctrine()->getRepository('AppBundle:Product');
// query for a single product by its primary key (usually "id")// 通过主键(通常是id)查询一件产品
$product = $repository->find($productId); // dynamic method names to find a single product based on a column value// 动态方法名称,基于字段的值来找到一件产品$product = $repository->findOneById($productId);$product = $repository->findOneByName('Keyboard');
// dynamic method names to find a group of products based on a column value
// 动态方法名称,基于字段值来找出一组产品$products = $repository->findByPrice(19.99); 
// find *all* products / 查出 *全部* 产品$products = $repository->findAll();

當然,你也可以使用複雜的查詢,參考 物件查詢 小節 。

你也可以有效利用findByfindOneBy 方法,基於多個條件來輕鬆取得物件:

$repository = $this->getDoctrine()->getRepository('AppBundle:Product'); // query for a single product matching the given name and price// 查询一件产品,要匹配给定的名称和价格$product = $repository->findOneBy(
    array('name' => 'Keyboard', 'price' => 19.99)); // query for multiple products matching the given name, ordered by price// 查询多件产品,要匹配给定的名称和价格$products = $repository->findBy(
    array('name' => 'Keyboard'),
    array('price' => 'ASC'));

渲染任何頁面時,你可以在調試工具列(web debug toolbar)的右下角看到許多查詢。

1466160351_18163_67861_doctrine_web_debug_toolbar (1).png

如果你點擊圖標,分析器(profiler)將會打開,顯示所產生的精確查詢。

如果你的頁面查詢超過了50個,圖示會變成黃色。這表示某些地方不大對勁。

#

物件更新 

一旦從Doctrine取得了一個對象,更新它就很容易了。假設你有一個路由,把一個產品id映射到controller的updateaction:

public function updateAction($productId){
    $em = $this->getDoctrine()->getManager();
    $product = $em->getRepository('AppBundle:Product')->find($productId);     if (!$product) {
        throw $this->createNotFoundException(
            'No product found for id '.$productId
        );
    }     $product->setName('New product name!');
    $em->flush();     return $this->redirectToRoute('homepage');}

更新一個物件包含三個步驟:

    ##從Doctrine中取出物件;
  1. 修改物件;
  2. 呼叫entity manager的
  3. flush() 方法。
注意呼叫

$em->persist($product) 是不必要的。回想一下,這個方法只是告訴Doctrine去管理或「觀察」 $product 物件。此處,因為你已經取到了 $product 物件了,它已經被管理了。

刪除物件 

刪除物件十分類似,但需要從entity manager呼叫

remove() 方法:

$em->remove($product);$em->flush();

你可能已經預期,

remove() 方法通知Doctrine你想從資料庫中刪除指定的entity。真正的 DELETE 查詢不會被真正執行,直到 flush() 方法被呼叫。

物件查詢 

你已經看到repository物件是如何讓你執行一些基本查詢而毋須做任何工作了:

$repository = $this->getDoctrine()->getRepository('AppBundle:Product'); $product = $repository->find($productId);$product = $repository->findOneByName('Keyboard');

當然,Doctrine 也允許你使用Doctrine Query Language(DQL)來寫一些複雜的查詢,DQL類似於SQL,只是它用於查詢一個或多個entity類別的物件(如

product) ,而SQL則是查詢一個資料表中的行(如product )。

在Doctrine中查詢時,你有兩個主要選擇:寫純正的Doctrine查詢(DQL) 或 使用Doctrine的Query Builder。

使用DQL進行物件查詢 

假設你要查詢價格高於

19.99 的產品,並且按價格從低到高排列。你可以使用DQL,Doctrine中類似原生SQL的語法,來建構一個用於此場景的查詢:

$em = $this->getDoctrine()->getManager();$query = $em->createQuery(
    'SELECT p
    FROM AppBundle:Product p
    WHERE p.price > :price
    ORDER BY p.price ASC')->setParameter('price', 19.99); $products = $query->getResult();

如果你習慣了寫SQL,那麼對於DQL也會非常自然。它們之間最大的不同就是你需要就「select PHP物件」來思考,而不是資料表的行。正因為如此,你要

AppBundle:Product 這個entity (可選的一個AppBundle\Entity\Product 類別的快捷寫法)來select,然後給entity一個p 的別名。

注意

setParameter() 方法。當使用Doctrine時,透過「佔位符」來設定任意的外部值(上面範例的 :price),是個好方法,因為它可以防止SQL注入攻擊。

#

getResult() 方法傳回一個結果陣列。要得到一個結果,可以使用getSingleResult()(這個方法在沒有結果時會拋出一個例外)或getOneOrNullResult()

$product = $query->setMaxResults(1)->getOneOrNullResult();

DQL語法強大到令人難以置信,允許輕鬆地在entity之間進行join(稍後會覆蓋relations)和group等。參考 Doctrine Query Language 文件以了解更多。

使用Doctrine's Query Builder進行物件查詢 

#不去寫DQL的大字串,你可以使用一個非常有用的QueryBuilder對象,來建立那個字串。當你的查詢取決於動態條件時,這很有用,因為隨著你的連接字串不斷增加,DQL程式碼會越來越難閱讀:

$repository = $this->getDoctrine()
    ->getRepository('AppBundle:Product'); // createQueryBuilder() automatically selects FROM AppBundle:Product// and aliases it to "p"// createQueryBuilder() 自动从 AppBundle:Product 进行 select 并赋予 p 假名$query = $repository->createQueryBuilder('p')
    ->where('p.price > :price')
    ->setParameter('price', '19.99')
    ->orderBy('p.price', 'ASC')
    ->getQuery(); $products = $query->getResult();// to get just one result: / 要得到一个结果:// $product = $query->setMaxResults(1)->getOneOrNullResult();

QueryBuilder物件包含了創建查詢時的所有必要方法。透過呼叫getQuery()方法,query builder將傳回一個標準的Query對象,可用來取得請求的結果集。

Query Builder更多信息,參考Doctrine的 Query Builder 文件。

把自訂查詢組織到Repository類別中 

#前面所有的查詢是直接寫在你的控制器裡的。但對於程式的組織來說,Doctrine提供了一個專門的repository類,它允許你保存所有查詢邏輯到一個中心位置。

參考 如何建立自訂Repository類別 以了解更多。

設定 

Doctrine是高度可設定的,雖然你可能永遠不會去關心那些選項。要了解Doctrine的設定信息,請參考 config reference。

Doctrine欄位類型參考 ¶

Doctrine配備了大量可用的欄位類型。每一個都能把PHP資料型別對應到特定的欄位類型中,無論你使用什麼資料庫。對於每一個欄位類型, Column 都可以被進一步配置,可以設定 lengthnullable 行為,name 或其他選項。可用欄位類型的列表,參考 Mapping Types documentation。

Associations(關係) 和 Relations(關聯) ¶

Doctrine 提供了你所需要的管理資料庫關係(也被稱為關聯-associations)的所有的功能。更多信息,參考 如何使用Doctrine Associations / Relations。

總結 ¶

有了Doctrine,你可以集中精力到你的 物件 以及 如何把它應用到程式中,而資料庫持久化則是第二位。這是因為Doctrine允許你使用任何的PHP物件來保存你的數據,並且依靠「元資料映射」資訊來把一個物件的資料映射到一個特定的資料表之中。

Doctrine有很多強大的功能等著你去學習,像是relationships(關聯),複雜查詢和事件監聽。