Pommbundle Связь с другим столом
Для моего проекта я использую pommbundle для своего проекта Symfony, и у меня есть вопрос:
Например:
СТОЛ Каталог: id = 1 имя = тест webinfo = 2
ТАБЛИЦА Информация: ID = 1 webid = 2 textinfo = ОК textmore = это тест
Связь
Catalogue.webinfo = Info.webid
Если моя сущность имеет отношение к другой сущности, определенной в схеме, и я хочу, чтобы объект содержал всю информацию, как получить доступ к информации, потому что дамп "Каталог" возвращает только целое число для "вебинфо". Нужно ли создавать свой собственный метод? В комплекте есть метод?
Можно ли показать базовый пример для использования в symfony2?
Спасибо вам
2 ответа
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","jules.vernes@gmail.com", … )
Postgres может возвращать строку Author непосредственно в наборе результатов постов в блоге, это намного более эффективно, чем предыдущее решение, но это может вызвать проблемы с производительностью, если записи автора большие. Может быть интересно добровольно ограничить количество авторских полей, извлекаемых в сообщениях в блоге, возможно, достаточно просто названия. Давайте выполним такой запрос в модели поста блога:
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')]));
Также можно извлечь весь вложенный экземпляр Author, просто изменив проекцию в методе:
$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 это ОРМ.
Спасибо вам за все, у меня есть только вторая ошибка в моем коде. Исправление:
public function findWithJointureAll(Where $condition = null)
{
$famille_model = $this
->getSession()
->getModel('\AppBundle\Entity\MyDb1\PublicSchema\FamilleModel')
;
$condition = (new Where)->andWhere($condition);
$sql ="
select
{projection}
from
{ssfamille} ssf
inner join {famille} fam ON ssf.\"Famille\" = fam.\"ID\" where {condition}";
$projection = $this->createProjection()
->setField('test', 'fam','"Famille"')
;
$sql = strtr(
$sql,
[
'{ssfamille}' => $this->structure->getRelation(),
'{famille}' => $famille_model->getStructure()->getRelation(),
'{projection}' => $projection->formatFieldsWithFieldAlias('ssf'),
'{condition}' => $condition,
]
);
return $this->query($sql,$condition->getValues(),$projection);
}
Я хочу просто добавить $projection->formatFieldsWithFieldAlias ('ssf') и кавычки, потому что имя базы в верхнем регистре...
Спасибо за ваш комплект, он просто идеален!