# 数据库和表
我们将学习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)。
有以下数据库结构的例子
![](https://box.kancloud.cn/099c37476dbe9bad6cfb2f56eea314d9_334x355.png)
在下面的示例中,我们获取了提取的书籍的相关数据。 在作者属性(书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
- 原子操作