Pommbundle与另一个表的关系

时间:2017-04-11 16:31:55

标签: postgresql symfony pomm

对于我的项目,我使用pommbundle作为我的Symfony项目,我有一个问题:

例如:  

    TABLE Catalogue:
    id = 1
    name = test
    webinfo = 2

    TABLE Info :
    id=1
    webid = 2
    textinfo = OK
    textmore = it's test

关系

    Catalogue.webinfo = Info.webid

如果我的实体与另一个实体有关系在模式中定义并且我想要一个对象包含所有信息,那么如何访问信息因为转储“Catalog”只返回“webinfo”的整数。我必须创建我的自己的方法?捆绑包含一个方法?

是否可以显示一个基本示例,用于symfony2?

谢谢你

2 个答案:

答案 0 :(得分:1)

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可以直接在博客帖子的结果集中返回作者行,这比以前的解决方案效率更高,但如果作者记录很大,这仍然会导致性能问题。自愿限制在博客帖子实体中获取的作者字段的数量可能是有趣的,也许只是名称就足够了。让我们在博客文章模型中执行此类查询:

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是ORM。

答案 1 :(得分:0)

谢谢大家, 我的代码中只有第二个错误 纠正:

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-&gt; formatFieldsWithFieldAlias(&#39; ssf&#39;) et quote,因为名字基础为大写...

感谢您的捆绑,它非常完美!