POMM不是一個ORM,因此不提供,自動將獲取關係的方法。
這種選擇是因爲大多數程序員習慣的簡單狀態的取得:
$blog_posts = $orm->getBlogPosts(); // SELECT * FROM blog.post;
foreach ($blog_posts as $blog_post) {
printf(
"The post titled '%s' has been written by '%s'.\n",
$post->getTitle(),
$post->getAuthor()->getName() // SELECT * FROM blog.author WHERE author_id = $*
);
}
,因爲有博客文章上面的代碼發出的作者表作爲許多查詢,這就是所謂的嵌套循環查詢,這是一個巨大的性能問題,因爲大多數程序員實際上並沒有看到它執行了那麼多的查詢。
你可以只用一個查詢做相同的SQL:
SELECT
title,
published_at,
… -- other fields
a AS author
FROM
blog.post p
LEFT JOIN blog.author a USING (author_id)
這將輸出線,如:
title | published_at | … | author
Gone with the wind | 2010-04-04 13:43:02… | … | ("Jules Vernes","[email protected]", …)
的Postgres可以直接在集合的結果返回作者一行博客帖子,這比以前的解決方案效率高得多,但如果作者記錄很大,這仍然會導致性能問題。自動限制在博客帖子實體中獲取的作者字段的數量可能很有趣,也許只是名字就夠了。讓我們在博客文章模型進行這樣的查詢:
class PostModel extends Model
{
// …
public function getWithAuthor()
{
// HINT: this is bad practice, read below.
$sql = <<<SQL
select P.post_id, P.title, …, A.name AS author_name
from blog.post P
left join blog.author A using (author_id)
SQL;
return $this->query($sql);
}
在控制器中,則容易與附加的作者信息,以獲取博客文章:
$blog_posts = $this->get('pomm')['my_session']
->getModel(PostModel::class)
->getWithAuthor();
foreach ($blog_posts as $post) {
printf(
"Post '%s' has been written by '%s'.\n",
$post['title'],
$post['author_name']
);
}
但這種方法是不能,因爲非常便攜每個關係(表格)的名稱都是硬編碼的,投影也是如此(SELECT部分中的字段)。更改數據庫結構會毀了這個查詢。這裏有一個方法來規避:
class PostModel extends Model
{
// …
public function getWithAuthor(Where $condition = null)
{
$condition = (new Where)->andWhere($condition); // empty condition and empty condition => true.
$sql = <<<SQL
select {projection}
from {post} P
left join {author} A using (author_id)
where {condition}
SQL;
$projection = $this->createProjection() // use Post fields
->setField('author_name', 'A.name', 'text'); // add a new field with its type
$author_relation = $this->getSession()
->getModel(AuthorModel::class) // get author relation name
->getStructure()
->getRelation();
$sql = strtr( // transform the SQL
$sql,
[
'{projection}' => $projection->formatFieldsWithFieldAlias("P"),
'{post}' => $this->structure->getRelation(),
'{author}' => $author_relation,
'{condition}' => $condition,
]);
return $this->query($sql, $condition->getValues(), $projection);
}
如果我們需要,因爲昨天他們的作者姓名獲取所有博客帖子?
$blog_posts = $this->get('pomm')['my_session']
->getModel(PostModel::class)
->getWithAuthor(new Where("published_at > $*::timestamptz", [new \DateTime('yesterday')]));
也可以抓取背面整體嵌套者實例,只是改變投影在該方法中:
$projection = $this->createProjection()
->setField('author', 'A', 'blog.author');
注:上面的字段的類型是表格,其中行起源。在Postgres中創建表意味着創建一個類型。
在控制器:
foreach ($blog_posts as $post) {
printf(
"Post '%s' has been written by '%s'.\n",
$post['title'],
$post['author']['name']
);
}
Postgres的是ORM。