Orm 条令-访问保存在链接表上的元数据

Orm 条令-访问保存在链接表上的元数据,orm,doctrine,many-to-many,inner-join,Orm,Doctrine,Many To Many,Inner Join,我有三张桌子: # schema.yml Author: connection: store-rw-library tableName: lib_author actAs: { Timestampable: ~ } columns: id: type: integer(4) unsigned: 1 primary: true autoincrement: true name: type: string(50) notnu

我有三张桌子:

# schema.yml
Author:
  connection: store-rw-library
  tableName: lib_author
  actAs: { Timestampable: ~ }
  columns:
    id:
    type: integer(4)
    unsigned: 1
    primary: true
    autoincrement: true
  name:
    type: string(50)
    notnull: true

Book:
  connection: store-rw-library
  tableName: lib_book
  actAs: { Timestampable: ~ }
  columns:
    id:
    type: integer(4)
    unsigned: 1
    primary: true
    autoincrement: true
  name:
    type: string(50)
    notnull: true
  relations:
    Author:
      class: Author
      foreignAlias: Books
      refClass: LinkingAuthorBook

LinkingAuthorBook:
  connection: store-rw-library
  tableName: lib_linking_author_book
  columns:
    author_id:
      type: integer(4)
      unsigned: 1
      primary: true
    book_id:
      type: integer(4)
      unsigned: 1
      primary: true
    created_at:
      type: timestamp(25)
      notnull: true
  relations:
    Author:
      foreignAlias: AuthorBooks
    Book:
      foreignAlias: AuthorBooks
根据notes via,我使用LinkingAuthorBook表在Author和Book之间建立了M:M的关系

现在,我试图在一个查询中获得由特定作者编写的所有书籍,如:

class AuthorTable
{
    public function getAuthor($id)
    {
        $q = Doctrine_Query::create()
            ->select('a.id AS author_id')
            ->addSelect('a.name AS author_name')
            ->addSelect('b.AuthorBooks')
            ->from('Author a')
            ->innerJoin('a.Books b')
            ->where('a.id = ?', $id);

        $result = $q->fetchArray();            
    }
}
来自上述DQL构造的结果查询:

SELECT
  m.id AS m__id,
  m.name AS m__1,
  m2.id AS m2__id,
  m2.name AS m2__1,
  m.id AS m__0,
  m.name AS m__1
FROM 
  lib_author m
INNER JOIN
  lib_linking_author_book m3 ON (m.id = m3.author_id)
INNER JOIN
  lib_book m2 ON m2.id = m3.book_id
WHERE
  (m.id = '163')
从上面的查询中,我看到它正确地进行了连接,但是如何访问在schema.yml文件中建立的LinkingAuthorBook.created_at metadata列呢

我能够访问元数据列的唯一方法是向LinkingAuthorBook添加一个显式的innerJoin,并使用关联的book_链接别名,但这会在生成的SQL中产生另一个连接。这没有意义,因为它可以从原始查询访问所需的数据

-更新3.7.2012-

问题仍然存在,如果我设置一个循环来迭代属于某个作者的所有书籍,我无法在不强制另一个查询的情况下组合LinkingAuthorBook表或Book表中的元数据

更新的查询:

$q = Doctrine_Query::create()
    ->from('Author a')
    ->innerJoin('a.Books b')
    ->innerJoin('b.LinkingAuthorBook ab ON a.id = ab.author_id AND b.id = ab.book_id')
    ->where('a.id = ?', $id);
链接AuthorBook->Book的循环示例:

foreach ($author->getLinkingAuthorBook() as $link) {

    // Works fine, no extra query
    var_dump($link->getCreatedAt());

    // Forces an extra query, even though 'name' is the column name
    //  So even though doctrine uses lazy-load, it should be able to 
    //  get this data from the original query
    var_dump($link->getBook()->getName());  
}
对于Book->LinkingAuthorBook的以下循环也是如此:

foreach ($author->getBook() as $book) {

    // Forces extra query
    var_dump($book->getLinkingAuthorBook()->getCreatedAt());

    // No extra query
    var_dump($book->getName());
}
我的工作重点是:

class Book
{
    public $meta;
}

class AuthorTable
{
    public function getAuthor($id) 
    {
        $q = Doctrine_Query::create()
            ->from('Author a')
            ->innerJoin('a.Books b')
            ->innerJoin('b.LinkingAuthorBook ab ON a.id = ab.author_id AND b.id = ab.book_id')
            ->where('a.id = ?', $id);

        $author = $q->fetchOne();

        // Manually hydrate Book Meta
        foreach ($author->getLinkingAuthorBook() as $authorBook) {
            $authorBooks[$authorBook->getId()] = $authorBook;
        }

        foreach ($author->getBook() as $book) {
            $book->meta = $authorBooks[$book->getId()];
        }
    }
}
现在,我可以使用meta对书籍进行迭代,而无需强制执行额外的查询:

foreach ($author->getBook() as $book) {

    // No extra query
    var_dump($book->meta->getCreatedAt());

    // No extra query
    var_dump($book->getName());
}
-更新3.8.2012-

因此,我能够在以下代码中证明:

foreach ($author->getBooks() as $book)
{
    echo $book->getName().'- '.$book->LinkingAuthorBook[0]->getCreatedAt().'<br/>';
}
然后我跟踪了/var/log/mysql/querys.log,能够看到生成的其他查询。因此,据我所知,在初始查询后手动水合Book::Meta对象是访问元数据的唯一方法,而无需发出另一个查询。

我的建议:

//one query for fetching an Author, his books and created_at for the each book
$q = Doctrine_Query::create()
            ->from('Author a')
            ->innerJoin('a.Books b')
            ->innerJoin('b.LinkingAuthorBook ab ON a.id = ab.author_id AND b.id = ab.book_id')
            ->where('a.id = ?', 1);

$author = $q->fetchOne();

echo 'Author: '.$author->getName().'<br/>';
echo 'Books: <br/>';
foreach ($author->getBooks() as $book)
{
    echo $book->getName().'- '.$book->LinkingAuthorBook[0]->getCreatedAt().'<br/>';
}

只有一个你真正需要的查询。

Lol,这使得谷歌的搜索已经开始。循环引用ftw。是否发出另一个查询?我被发现使用对象只是为了发现我从数组移植到ORM的页面从2个查询变成了21个查询。因此我将fetchArray切换到fetchOne,以获得对对象的访问权,从而支持上面描述的流畅界面。我可以做var_dump$result->getId;它是有效的,但当我使用var_dump$result->getName;它添加了另一个查询:选择m.id作为m\u id,选择m.name作为m\u name,选择m.created\u at作为m\u created\u at,选择m.updated\u at作为m\u updated\u at FROM lib\u author m,其中m.id='163'限制1。这是没有意义的,为什么当我试图检索已知访问器抛出的数据时,它会发出另一个查询?使用延迟加载模式。在查询中,您选择一个作者名而不是姓名,请参见:a.name作为作者名您可以使用$result->getAuthorName访问它。当您尝试使用$result->getName命令访问name时,请生成另一个查询以检索名称。更新的帖子,让我知道您的想法。谢谢更新。我修改了你提供的信息,并在OP的第二次更新中发布了我的发现。
//one query for fetching an Author, his books and created_at for the each book
$q = Doctrine_Query::create()
            ->from('Author a')
            ->innerJoin('a.Books b')
            ->innerJoin('b.LinkingAuthorBook ab ON a.id = ab.author_id AND b.id = ab.book_id')
            ->where('a.id = ?', 1);

$author = $q->fetchOne();

echo 'Author: '.$author->getName().'<br/>';
echo 'Books: <br/>';
foreach ($author->getBooks() as $book)
{
    echo $book->getName().'- '.$book->LinkingAuthorBook[0]->getCreatedAt().'<br/>';
}