Doctrine2 ORM OneToOne不工作更新更改为many many,但不能完全工作


Doctrine2 ORM OneToOne not working UPDATE changed to ManyToMany but not fully working

我有2个表叫广告和用户。用户Id写入到广告表中。现在我已经创建了第三个名为Bookmark的表。表有2列,advert_id和user_id。当我看到一个我喜欢的广告,我可以添加一个书签,以便能够更容易地找到它在我的私人部分。当我在Private Section中查看我的书签时,我希望直接看到广告详细信息,因此在我的Repository中,我希望创建一个Join来读取广告表中的信息。我以为这将是一种一对一的关系。我还必须确保如果广告被删除,那么所有的书签都需要被删除,所以我认为这是一个双向关系。下面是:

实体/Bookmark.php

 /**
 * Bookmark
 *
 * @ORM'Table(name="bookmark")
 * @ORM'Entity(repositoryClass="Advert'Repository'BookmarkRepository")
 */
class Bookmark
{
 /**
 * @var integer
 * @ORM'Id
 * @ORM'Column(name="advert_id", type="integer", nullable=false)
 * @ORM'OneToOne(targetEntity="Advert", mappedBy="bookmark")
 * @ORM'JoinColumn(name="advert_id", referencedColumnName="id")
 */
 private $advertId;
/**
 * @var integer
 * @ORM'Id
 * @ORM'Column(name="user_id", type="integer", nullable=false)
 * @ORM'OneToOne(targetEntity="User")
 * @ORM'JoinColumn(name="user_id", referencedColumnName="id")
 */
 private $userId;

 public function setAdvertId($advertId)
 {
    $this->advertId = $advertId;
    return $this;
 }

 public function getAdvertId()
 {
    return $this->advertId;
 }

 public function setUserId($userId)
 {
    $this->userId = $userId;
    return $this;
 }

 public function getUserId()
 {
    return $this->userId;
 }

实体' Advert.php

/** Advert
 * 
 * @ORM'Table(name="advert")
 * @ORM'Entity(repositoryClass="Advert'Repository'AdvertRepository")
 */
class Advert
{
  /**
   * @var integer
   *
   * @ORM'Column(name="id", type="integer", nullable=false)
   * @ORM'Id
   * @ORM'GeneratedValue(strategy="IDENTITY")
   */
    private $id;
 /**
   * @ORM'OneToOne(targetEntity="Bookmark", inversedBy="advert")
   * @ORM'JoinColumn(name="id", referencedColumnName="advert_id")
   **/
    private $bookmark;
public function setBookmark($bookmark)
{
    $this->bookmark = $bookmark;
    return $this;
}

public function getBookmark()
{
    return $this->bookmark;
}

public function addBookmark($bookmark)
{
    $this->bookmark->add($bookmark);
}

public function removeBookmark($bookmark)
{
    $this->bookmark->removeElement($bookmark);   
}

广告' Repository '广告' Repository.php

class BookmarkRepository extends EntityRepository
{
  public function getBookmarksByUserIds($userId)
  {
    $query =$this->_em->getRepository($this->getEntityName())->createQueryBuilder('b')
                            ->join('b.advertId', 'a')
                            ->andWhere('a.userId=:userid')
                            ->setParameter('userid',$userId)       
            ;
    return $query->getQuery()->getResult();
  }

我做错了什么,我的误解在哪里?我得到错误信息:

广告'实体'书签没有名为advertId的关联

正如我所说,表Bookmark得到填充,只有当我点击"添加广告到书签"。我需要一个连接,能够显示广告的详细信息,当我点击"显示我的书签",如果一个广告或用户被删除,所有的书签需要从书签表中删除。这是一种一对一的双向关系吗?哪里出了问题?

我已经更新了下面的2个文件,但我没有得到任何书签显示。相反,我应该看到书签广告列表加上广告的详细信息。我甚至还没有尝试过让我的"书签广告"服务或检查广告是否被书签的方法再次工作。我以前是能用的,但我想我现在真的很困惑。

AdvertController.php

public function watchlistAction()
{
    $user_id = $this->zfcUserAuthentication()->getIdentity()->getId();
    $adverts = $this->getEntityManager()->getRepository('Advert'Entity'User')->findBookmarksByUserId($user_id);
        return new ViewModel(array(
            'adverts' => $adverts,
        ));
}

库' UserRepository.php

class UserRepository extends EntityRepository
{
  public function findBookmarksByUserId($userId)
  {
      $query =$this->_em->getRepository($this->getEntityName())->createQueryBuilder('b')
                            ->join('b.bookmarks', 'a')
                            ->join('b.adverts', 'c')
                ->andWhere('a.user=:userid')
                ->setParameter('userid',$userId)       
            ;
      return $query->getQuery()->getResult();
  }

你是对的,我不需要UserRepository查询,请参阅书签广告列表。我只需要改变

AdvertController.php

public function watchlistAction()
{
        $user_id = $this->zfcUserAuthentication()->getIdentity()->getId();
        // get User by reference (no queries executed)
        $user = $this->getEntityManager()->getReference('Advert'Entity'User' , $user_id);
        $adverts = $user->getBookmarks();
        return new ViewModel(array(
            'adverts' => $adverts,
        ));
}

还有一个好消息,当我删除一个广告时,Bookmark会自动从Bookmark Database表中删除。现在我只需要找出如何添加书签,所以我将不得不更改我的服务。一旦我得到这个工作,我会更新这篇文章给别人看。

不幸的是,我没有得到下面3个方法在我的服务工作。显然我现在必须选择1条记录,要么检查状态(书签已经或没有),删除书签(由advertId定义)或添加书签(由advertId定义)

public function checkAdvertBookmarkStatus($advertId)
{
    $userId = $this->getUserEntity()->getId();  
    // get User by reference (no queries executed)
    $user = $this->getEntityManager()->getReference('Advert'Entity'User' , $userId);
    $bookmarkStatus = $this->getEntityManager()->getRepository('Advert'Entity'User')
                                         ->findOneBy(array('advert' => $advertId, 'userId' => $userId));
    return $bookmarkStatus;
}  
   public function saveAdvertBookmark($advertId)
{
    $bookmark = new UserEntity();
    $userId = $this->getUserEntity()->getId();
 //   $bookmark->addBookmark($advertId);
    $bookmark->setAdvertId($advertId);
    $bookmark->setUserId($userId);
    # write new bookmmark to database tbl bookmark
    $this->getEntityManager()->persist($bookmark);
    $this->getEntityManager()->flush();
}

public function removeAdvertBookmark($advertId)
{
    $bookmark = new UserEntity();
    $userId = $this->getUserEntity()->getId();
    $bookmark = $this->getEntityManager()->getRepository('Advert'Entity'Bookmark')
                                         ->findOneBy(array('advertId' => $advertId, 'userId' => $userId));
    # remove bookmmark from tbl bookmark
    $this->getEntityManager()->remove($bookmark);
    $this->getEntityManager()->flush();
}

我想答案在教程中,我一直在阅读,但我不完全理解它。我能够添加书签之前,当我使用BookmarkEntity,但我不知道如何通过UserEntity

OneToOne关系在这里是错误的选择,这意味着一个用户只能收藏一个广告,而一个广告只能被一个用户收藏。因为一个用户应该能够收藏很多广告,而一个广告应该被很多用户收藏,所以你需要一个多多多的关系。

如果您使用的是数据库,那么创建映射表书签的想法是没有错的。然而,您不需要在Doctrine中将其创建为实体。您可以简单地在一个名为bookmarks in User的关联中添加广告,以显示书签广告,反之亦然:

用户实体:

/**
 * @var integer
 *
 * @ORM'Column(name="id", type="integer", nullable=false)
 * @ORM'Id
 * @ORM'GeneratedValue(strategy="IDENTITY")
 */
private $id;
/**
 * @ORM'ManyToMany(targetEntity="Application'Entity'Advert", inversedBy="bookmarks", cascade={"persist"})
 * @ORM'JoinTable(name="bookmarks",
 *      joinColumns={@ORM'JoinColumn(name="user_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM'JoinColumn(name="advert_id", referencedColumnName="id")}
 *      )
 */
private $bookmarks;

广告实体

/**
 * @var integer
 *
 * @ORM'Column(name="id", type="integer", nullable=false)
 * @ORM'Id
 * @ORM'GeneratedValue(strategy="IDENTITY")
 */
private $id;
/**
 * @ORM'ManyToMany(targetEntity="Application'Entity'User", mappedBy="bookmarks", cascade={"persist"})
 * @ORM'JoinTable(name="bookmarks",
 *      joinColumns={@ORM'JoinColumn(name="advert_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM'JoinColumn(name="user_id", referencedColumnName="id")}
 *      )
 */
private $bookmarks;

你可能也想看看这篇文章:http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-associations.html

编辑:如何添加和删除书签

Doctrine中的关联与字段完全不同,尽管它们都是实体中的属性。要处理书签,您可以直接在用户实体中添加或删除广告实体。例如:

$bookmarks = $user->getBookmarks();
$bookmarks[] = $advert;

这将为用户添加一个书签,并将在您完成persistflush后立即存储。为了更简单,您可以定义removeradder:

使用语句:

use Doctrine'Common'Collections'ArrayCollection;
use Doctrine'Common'Collections'Collection;

和代码:

/**
 * @param Collection $bookmarks
 */
public function addBookmarks(Collection $bookmarks)
{
    foreach ($bookmarks as $bookmark) {
        $this->bookmarks->add($bookmark);
    }
}
/**
 * @param Collection $bookmarks
 */
public function removeBookmarks(Collection $bookmarks)
{
    foreach ($bookmarks as $bookmark) {
        $this->bookmarks->removeElement($bookmark);
    }
}

你现在可以像这样删除和添加在集合中给出的广告:

$user->addBookmarks(new ArrayCollection(array($advert)));

总是建议在许多关系中定义adderremover,因为许多Doctrine组件将需要它们,例如非常有用的DoctrineObject, DoctrineModule在Zend 2中使用的一个水合器