# 數據庫和表
我們將學習Nette框架中數據庫“表”層的基礎知識。
Nette\Database\Table層幫助您更容易地以更優化的方式獲取數據庫數據。 主要的態度是只從一個表中提取數據,并立即提取它們。 將數據提取到ActiveRow實例中。 來自由關系連接的其他表的數據由另一個查詢傳遞 - 這由數據庫\表層本身維護。
~~~
讓我們來看看常見的用例。 你需要獲取書籍和作者數據。 它是普通的1:N關系。 常用的實現通過一個具有表連接的SQL查詢提取數據。 第二種可能性是單獨獲取數據,運行一個查詢以獲取圖書,然后通過另一個查詢(例如在您的foreach循環中)為每本圖書獲取作者。 這可以很容易地優化為只運行兩個查詢,一個用于書籍,另一個用于所需的作者 - 這只是Nette \ Database \ Table的工作方式。
~~~
Database\Table層提供了Selection實例,作為一個數據庫表中的數據選擇。 選擇實例可幫助您過濾所需的數據并將其作為ActiveRow實例提取。
創建選擇很容易,只需在數據庫上下文中調用table()方法。 看看如何在Nette \ Database一章中獲取或創建上下文實例。
~~~
$selection = $context->table('book'); // db表名稱是 "book"
~~~
選擇工具Traversable接口:你可以只是迭代實例來獲取所有的書。 行作為ActiveRow實例提取; 您可以從其屬性中讀取行數據。
~~~
$books = $context->table('book');
foreach ($books as $book) {
echo $book->title;
echo $book->author_id;
}
~~~
只有一個特定的行由Selection :: get()方法完成。 它是“過濾”方法,它直接返回一個ActiveRow實例。
~~~
$book = $context->table('book')->get(2); // 返回ID為2的書
echo $book->title;
echo $book->author_id;
~~~
## 使用關系
正如我們在章節介紹中提到的,Database\Table層為您維護表關系。 有兩種可能性如何和在哪里可以與關系工作。
1、過濾選擇獲取的行。 在介紹中,我們說明了一次只從一個數據庫表中選擇數據的基本原理。 但是,Selection實例可以執行表連接以篩選所選行。 例如,您只需要選擇寫入超過2本書的作者。 有關詳細概述,請參閱數據庫:選擇一章。
2、獲取獲取的ActiveRows的相關數據。 我們拒絕同時從多個表中獲取數據。 可悲的是,打印author_id不夠好。 我們需要獲得完整的作者數據庫行,理想情況下作為ActiveRow提取。 獲得這種類型的關系由ActiveRow維護。 有關詳細信息,請參閱數據庫:ActiveRow章節。
在提供的示例中,我們將使用下面的數據庫模式。 有常見的OneHasMany和ManyHasMany關系。 OneHasMany關系加倍,一本書必須有一個作者,可以有一個翻譯(translator_id可能是一個NULL)。
有以下數據庫結構的例子

在下面的示例中,我們獲取了提取的書籍的相關數據。 在作者屬性(書ActiveRow實例)中有另一個ActiveRow實例,它表示書的作者。 獲取book_tag實例是由related()方法完成的,它返回這個實例的集合。 在循環中,我們從book_tag實例中可用的另一個ActiveRow實例獲取標記名稱。 有關獲取相關數據的詳細概述,請參閱數據庫:ActiveRow章節。
~~~
$books = $context->table('book');
foreach ($books as $book) {
echo 'title: ' . $book->title;
echo 'written by: ' . $book->author->name;
echo 'tags: ';
foreach ($book->related('book_tag') as $bookTag) {
echo $bookTag->tag->name . ', ';
}
}
~~~
你會很高興數據庫層的工作效率。 上面的示例執行常量查詢,請參閱以下4個查詢:
~~~
SELECT * FROM `book`
SELECT * FROM `author` WHERE (`author`.`id` IN (11, 12))
SELECT * FROM `book_tag` WHERE (`book_tag`.`book_id` IN (1, 4, 2, 3))
SELECT * FROM `tag` WHERE (`tag`.`id` IN (21, 22, 23))
~~~
如果您使用緩存(默認值),則不會不必要地查詢列。 第一次查詢后,緩存將存儲使用的列名稱,Nette \ Database將僅運行具有所需列的查詢:
~~~
SELECT `id`, `title`, `author_id` FROM `book`
SELECT `id`, `name` FROM `author` WHERE (`author`.`id` IN (11, 12))
SELECT `book_id`, `tag_id` FROM `book_tag` WHERE (`book_tag`.`book_id` IN (1, 4, 2, 3))
SELECT `id`, `name` FROM `tag` WHERE (`tag`.`id` IN (21, 22, 23))
~~~
- Nette簡介
- 快速開始
- 入門
- 主頁
- 顯示文章詳細頁
- 文章評論
- 創建和編輯帖子
- 權限驗證
- 程序員指南
- MVC應用程序和控制器
- URL路由
- Tracy - PHP調試器
- 調試器擴展
- 增強PHP語言
- HTTP請求和響應
- 數據庫
- 數據庫:ActiveRow
- 數據庫和表
- Sessions
- 用戶授權和權限
- 配置
- 依賴注入
- 獲取依賴關系
- DI容器擴展
- 組件
- 字符串處理
- 數組處理
- HTML元素
- 使用URL
- 表單
- 驗證器
- 模板
- AJAX & Snippets
- 發送電子郵件
- 圖像操作
- 緩存
- 本土化
- Nette Tester - 單元測試
- 與Travis CI的持續集成
- 分頁
- 自動加載
- 文件搜索:Finder
- 原子操作