ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# 数据库:ActiveRow Selection所返回的每一行由ActiveRow实例表示。 此类提供用于访问已提取列的标准接口。 您可以读取数据作为属性或通过数组访问。 如果列不存在,则抛出MemberAccessException。 您可以检查列是否由标准isset结构设置。 ~~~ echo $book->id; echo $book['title']; isset($book->id); isset($book['title']); ~~~ 请注意,即使提取列,但值为NULL,isset也会返回FALSE。 ## 关系 主要的Nette\Database\Table原理是分别从不同的表中提取数据。 此行为由Nette\Database本身维护,行的相关数据将同时为所有其他行提取。 我们有两种简单的关系类型:“有一个”和“有很多”。 我们将使用DiscoveredConventions,它从你的数据库中获取关系。 ## 一对一关系 一对一关系是一个常见的用例。 书有一个作者。 书有一个翻译。 获取相关行主要由ref()方法完成。 Ref()方法接受两个参数:目标表名和源连接列。 参见示例: ~~~ $book = $context->table('book')->get(1); $book->ref('author', 'author_id'); ~~~ 在上面的示例中,我们从作者表获取相关作者条目,作者主键由book.author_id列搜索。 如果没有适当的条目,Ref()方法返回ActiveRow实例或NULL。 返回的行是ActiveRow的一个实例,所以我们可以使用与书条目相同的方式。 ~~~ $author = $book->ref('author', 'author_id'); $author->name; $author->born; // or directly $book->ref('author', 'author_id')->name; $book->ref('author', 'author_id')->born; ~~~ 书也有一个翻译,所以得到翻译名称是很容易。 ~~~ $book->ref('author', 'translator_id')->name ~~~ 所有这一切都很好,但它有点麻烦,你不觉得吗? 数据库已经包含外键定义,为什么不自动使用它们? 让我们这样做! 如果我们调用property不存在,ActiveRow尝试将调用属性名称解析为“has one”关系。 获取此属性与调用只有一个参数的ref()方法相同。 我们将调用唯一的参数key。 键将被解析为特定的外键关系。 传递的键与行列匹配,如果匹配,则在匹配列上定义的外键用于从相关目标表获取数据。 参见示例: ~~~ $book->author->name; // same as $book->ref('author')->name; ~~~ ActiveRow实例没有作者列。 将搜索所有图书列与键匹配。 在这种情况下匹配意味着列名称必须包含键。 因此,在上面的示例中,author_id列包含字符串“author”,因此与“author”键匹配。 如果你想得到图书翻译,只需要使用例如。 “translator”作为键,因为“translator”键将匹配translator_id列。 您可以在“加入表达式”章节中找到有关键匹配逻辑的更多信息。 ~~~ echo $book->title . ": "; echo $book->author->name; if ($book->translator) { echo " (translated by " . $book->translator->name . ")"; } ~~~ 如果您要获取多本图书,应该使用相同的方法。 Nette \ Database将同时获取所有提取的图书的作者和翻译者。 ~~~ $books = $context->table('book'); foreach ($books as $book) { echo $book->title . ": "; echo $book->author->name; if ($book->translator) { echo " (translated by " . $book->translator->name . ")"; } } ~~~ 代码将只运行这3个查询: ~~~ SELECT * FROM `book`; SELECT * FROM `author` WHERE (`id` IN (1, 2, 3)); -- ids of fetched books from author_id column SELECT * FROM `author` WHERE (`id` IN (2, 3)); -- ids of fetched books from translator_id column ~~~ ## 多对多关系 “多对我”关系只是扭转了“一对一”关系。 作者写了很多书。 作者翻译了很多书。 正如你可以看到的,这种类型的关系是有点困难,因为关系是“命名”(“书面”,“翻译”)。 ActiveRow实例具有related()方法,它将返回相关条目的数组。 条目也是ActiveRow实例。 参见下面的例子: ~~~ $author = $context->table('author')->get(11); echo $author->name . " has written:"; foreach ($author->related('book.author_id') as $book) { echo $book->title; } echo "and translated:"; foreach ($author->related('book.translator_id') as $book) { echo $book->title; } ~~~ Related()方法接受作为两个参数传递的完整连接描述或作为由点连接的一个参数。 第一个参数是目标表,第二个是目标列。 ~~~ $author->related('book.translator_id'); // same as $author->related('book', 'translator_id'); ~~~ 您可以使用基于外键的Nette \ Database启发式方法,并且只提供关键参数。 键将与指向当前表(作者表)的所有外键进行匹配。 如果有匹配,Nette \ Database将使用这个外键,否则会抛出Nette \ InvalidArgumentException或AmbiguousReferenceKeyException。 您可以在“加入表达式”章节中找到有关键匹配逻辑的更多信息。 当然,你可以为所有获取的作者调用相关的方法,Nette \ Database将再次同时获取适当的书。 ~~~ $authors = $context->table('author'); foreach ($authors as $author) { echo $author->name . " has written:"; foreach ($author->related('book') as $book) { $book->title; } } ~~~ 上面的示例将只运行两个查询: ~~~ SELECT * FROM `author`; SELECT * FROM `book` WHERE (`author_id` IN (1, 2, 3)); -- ids of fetched authors ~~~