Doctrine2 ORM 访问多对多连接表
Posted
技术标签:
【中文标题】Doctrine2 ORM 访问多对多连接表【英文标题】:Doctrine2 ORM Access ManyToMany Join Table 【发布时间】:2015-09-25 08:28:07 【问题描述】:对我上一个问题的跟进
Doctrine2 ORM OneToOne not working UPDATE changed to ManyToMany but not fully working.
我接受了给出的非常有用的答案,因为它为我指明了正确的方向。不幸的是,我很难让其余的工作正常进行,但是由于问题太长且令人困惑,我开始了一个新问题。
我有一个用户可以在其中写广告的页面。用户还可以将希望稍后在其用户部分看到的广告添加为书签。
我有 3 个数据库表
advert (id, advert_title....)
user (id, user_name....)
bookmarks (advert_id, user_id)
按照我之前的问题中的建议,我创建了 2 个实体,广告和用户实体(见下文)
Advert.php
namespace Advert\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use DateTime;
use Zend\Stdlib\ArrayObject;
/** 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\ManyToMany(targetEntity="Advert\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;
public function __construct()
$this->categories = new ArrayCollection();
$this->images = new ArrayCollection();
$this->advertCreated = new \DateTime("now");
/**
* Set ID
*
* @param integer $id
* @return Advert
*/
public function setId($id)
$this->id = $id;
return $this;
/**
* Get id
*
* @return integer
*/
public function getId()
return $this->id;
/**
* Set bookmark
*
* @param $bookmark
* @return bookmark
*/
public function setBookmark($bookmark)
$this->bookmark = $bookmark;
return $this;
/**
* Get bookmark
*
* @return ArrayCollection
*/
public function getBookmark()
return $this->bookmarks;
/**
* @param Collection $bookmark
*/
public function addBookmark($bookmarks)
$this->bookmarks->add($bookmarks);
/**
* @param Collection $bookmark
*/
public function removeBookmark($bookmarks)
$this->bookmarks->removeElement($bookmarks);
User.php
namespace Advert\Entity;
use Doctrine\ORM\Mapping as ORM;
use ZfcUser\Entity\User as ZfcUser;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
/**
* User
* @ORM\Table(name="user")
* @ORM\Entity(repositoryClass="Advert\Repository\UserRepository")
*/
class User extends ZfcUser
/**
* @var integer
*
* @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @ORM\ManyToMany(targetEntity="Advert\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;
public function __construct()
$this->bookmarks = new ArrayCollection();
public function getBookmarks()
return $this->bookmarks;
/**
* @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);
我现在有一项服务来检查广告是否已被添加书签、删除书签或设置书签。这意味着我必须将 UserId 和 AdvertId 直接输入到加入表书签中。但是,如果我没有带有 setUserId 和 setAdvertId 的书签实体,我该怎么做?
到目前为止,这是我的服务,最后两种方法(保存和删除)显示了我在删除书签实体之前使用的内容。我现在如何阅读联接表以检查书签是否已经存在,以便检查 userId 和 advertId?再说一次,我将如何访问此表以直接删除书签?如果所有者删除了广告,则书签将被删除,这很好,但显然用户还需要能够只删除一个书签。我如何做到这一点?
BookmarkAdvertService.php
public function checkAdvertBookmarkStatus($advertId)
$userId = $this->getUserEntity()->getId();
$advert = $this->getEntityManager()->find('Advert\Entity\Advert', $advertId);
$bookmarkStatus= $advert->getBookmark();
return $bookmarkStatus;
public function saveAdvertBookmark($advertId)
//this is what I used before
$bookmark = new BookmarkEntity();
$userId = $this->getUserEntity()->getId();
// $bookmark->addBookmark($advertId); ??? like this
$bookmark->setAdvertId($advertId);
$bookmark->setUserId($userId);
# write new bookmmark to database tbl bookmark
$this->getEntityManager()->persist($bookmark);
$this->getEntityManager()->flush();
public function removeAdvertBookmark($advertId)
// this is what I used before
$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();
更新 1 不起作用
我收到 2 条错误消息:
get_class() expects parameter 1 to be object, string given
vendor\doctrine\common\lib\Doctrine\Common\Persistence\Mapping\MappingException.php:96
Message:
Class '' does not exist
广告\服务\书签广告服务.php
class BookmarkAdvertService
public function saveAdvertBookmark($advert)
$user = $this->getUserEntity()->getId();
# create a new, empty entity
$bookmark = new \Advert\Entity\Bookmark();
$bookmark->setUser($user);
$bookmark->setAdvert($advert);
# write new bookmmark to database tbl bookmark
$this->getEntityManager()->persist($bookmark);
$this->getEntityManager()->flush();
广告/实体/Bookmark.php
namespace Advert\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection;
/** Bookmark
*
* @ORM\Table(name="bookmarks")
* @ORM\Entity(repositoryClass="Advert\Repository\BookmarkRepository")
*/
class Bookmark
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="Advert\Entity\Advert", inversedBy="bookmark")
* @ORM\JoinColumn(name="advert_id", referencedColumnName="id")
*/
private $advert;
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="Advert\Entity\User", inversedBy="bookmark")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
public function setAdvert($advert)
$this->advert = $advert;
return $this;
public function getAdvert()
return $this->advert;
public function setUser($user)
$this->user = $user;
return $this;
public function getUser()
return $this->user;
广告\实体\广告.php
namespace Advert\Entity;
use Advert\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
/** 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\OneToMany(targetEntity="Bookmark", mappedBy="advert", cascade="persist", "remove")
* @ORM\JoinColumn(name="advert_id", referencedColumnName="id")
*/
private $bookmarks;
public function setBookmark($bookmark)
$this->bookmark = $bookmark;
return $this;
/**
* Get bookmark
*
* @return ArrayCollection
*/
public function getBookmarks()
return $this->bookmarks;
/**
* @param Collection $bookmarks
*/
public function removeBookmarks(Collection $bookmarks)
foreach ($bookmarks as $bookmark)
$this->bookmarks->removeElement($bookmark);
广告\实体\用户.php
namespace Advert\Entity;
use Doctrine\ORM\Mapping as ORM;
use ZfcUser\Entity\User as ZfcUser;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
/**
* User
*
* @ORM\Table(name="user")
* @ORM\Entity(repositoryClass="Advert\Repository\UserRepository")
*/
class User extends ZfcUser
/**
* @var integer
*
* @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* @ORM\OneToMany(targetEntity="Bookmark", mappedBy="user", cascade="persist", "remove")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $bookmarks;
public function __construct()
$this->bookmarks = new ArrayCollection();
public function getBookmarks()
return $this->bookmarks;
/**
* @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);
更新 2 工作中
public function saveAdvertBookmark($advertId)
$userId = $this->getUserEntity()->getId();
$user = $this->getEntityManager()->find('Advert\Entity\User', $userId);
$advert = $this->getEntityManager()->find('Advert\Entity\Advert', $advertId);
# create a new, empty entity
$bookmark = new \Advert\Entity\Bookmark();
$bookmark->setUser($user);
$bookmark->setAdvert($advert);
# write new bookmmark to database tbl bookmark
$this->getEntityManager()->persist($bookmark);
$this->getEntityManager()->flush();
public function removeAdvertBookmark($advert)
$user = $this->getUserEntity()->getId();
$advert = $this->getEntityManager()->getRepository('Advert\Entity\Bookmark')
->findOneBy(array('advert' => $advert, 'user' => $user));
if ($advert !== NULL)
# write new bookmmark to database tbl bookmark
$this->getEntityManager()->remove($advert);
$this->getEntityManager()->flush();
else
return false;
【问题讨论】:
【参考方案1】:您的映射似乎有误。
在我看来,您的书签本身也是一个实体。该实体有一个User
和一个Advert
。这两者结合起来创建了一个复合键。
所以从User
到Bookmark
的关系是一对多的。并为用户多对一添加书签。
从Advert
到Bookmark
的关系是一对多的,从Bookmark
到Advert
是多对一的。
您的Bookmark
实体应如下所示:
class Bookmark
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="Advert\Entity\Advert", inversedBy="bookmarks")
* @ORM\JoinColumn(name="advert_id", referencedColumnName="id")
*/
private $advert;
/**
* @ORM\Id
* @ORM\ManyToOne(targetEntity="User\Entity\User", inversedBy="bookmarks")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/**
* @param Advert $advert
* @return self
*/
public function setAdvert(Advert $advert)
$this->advert = $advert;
$advert->addBookMark($this);
return $this;
/**
* @return Advert
*/
public function getAdvert()
return $this->advert;
/**
* @param User $user
* @return self
*/
public function setUser(User $user)
$this->user = $user;
$user->addBookMark($this);
return $this;
/**
* @return User
*/
public function getUser()
return $this->user;
然后在你的User
:
/**
* @ORM\OneToMany(targetEntity="Advert\Entity\BookMark", mappedBy="user", cascade="remove")
*/
private $bookmarks;
/**
* @return Collection
*/
public function getBookmarks()
return $this->bookmarks;
/**
* @param BookMark $bookmark
*/
public function addBookmark(BookMark $bookmark)
$this->bookmarks->add($bookmark);
/**
* @param Collection $bookmarks
*/
public function addBookmarks(Collection $bookmarks)
foreach ($bookmarks as $bookmark)
$this->addBookMark($bookmark);
/**
* @param BookMark $bookmark
*/
public function removeBookmark(BookMark $bookmark)
$this->bookmarks->removeElement($bookmark);
/**
* @param Collection $bookmarks
*/
public function removeBookmarks(Collection $bookmarks)
foreach ($bookmarks as $bookmark)
$this->removeBookmark($bookmark);
在你的Advert
:
/**
* @ORM\OneToMany(targetEntity="Advert\Entity\BookMark", mappedBy="advert", cascade="remove")
*/
private $bookmarks;
/**
* @return Collection
*/
public function getBookmarks()
return $this->bookmarks;
/**
* @param BookMark $bookmark
*/
public function addBookmark(BookMark $bookmark)
$this->bookmarks->add($bookmark);
/**
* @param Collection $bookmarks
*/
public function addBookmarks(Collection $bookmarks)
foreach ($bookmarks as $bookmark)
$this->addBookMark($bookmark);
/**
* @param BookMark $bookmark
*/
public function removeBookmark(BookMark $bookmark)
$this->bookmarks->removeElement($bookmark);
/**
* @param Collection $bookmarks
*/
public function removeBookmarks(Collection $bookmarks)
foreach ($bookmarks as $bookmark)
$this->removeBookmark($bookmark);
为您服务:
/**
* @param int $advertId
*/
public function saveAdvertBookmark($advertId)
$entityManager = $this->getEntityManager():
$user = $this->getUserEntity();
$advert = $entityManager->find('Advert\Entity\Advert', $advertId):
$bookmark = new \Advert\Entity\Bookmark();
$bookmark->setUser($user);
$bookmark->setAdvert($advert);
$entityManager->persist($bookmark);
$entityManager->flush();
要在删除 User
或 Advert
时删除所有书签,只需在这些实体中的书签关系中添加 cascade="remove"
。
【讨论】:
以上是关于Doctrine2 ORM 访问多对多连接表的主要内容,如果未能解决你的问题,请参考以下文章
如何避免与 Doctrine2 和 Zend Framework 2 的多对多关系重复?
十一 .Django 多对多表ManyToManyField (ORM)