我有2个名为Advert and User的表。用户ID将写入广告表。我现在创建了一个名为Bookmark的第三个表。该表有2列,advert_id和user_id。当我看到我喜欢的广告时,我可以添加一个书签,以便能够在我的私人部分找到它。当我在我的私人部门看到我的书签时,我希望立即看到广告详细信息,因此在我的存储库中,我想创建一个Join来读取广告表中的信息。我认为这将是OneToOne关系。我还必须确保如果广告被删除,那么所有书签都需要删除,所以我认为它是双向关系。所以我有以下内容:
实体/ 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.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();
}
我做错了什么或我的误解在哪里?我收到错误信息:
Advert \ Entity \ Bookmark没有名为advertId的关联
正如我所说,当我点击“添加广告到书签”时,表格Bookmark才会被填充。当我点击“显示我的书签”时,我需要加入才能显示广告详细信息,如果广告或用户被删除,则需要从书签表中删除所有书签。这是一个OneToOne双向关系,有什么问题?
更新1以下不工作
我已更新下面的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();
}
更新2以下工作
你是对的,我不需要UserRepository Query查看Bookmarked Adverts列表。我只需要改变
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,
));
}
好消息是,在我删除广告时,书签会自动删除在书签数据库表中。现在我只需要找出如何添加书签,所以我将不得不改变我的服务。一旦我开始工作,我将更新这篇文章供其他人查看。
更新3以下不工作
不幸的是,我的服务工作中没有得到以下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来实现它
答案 0 :(得分:2)
OneToOne关系在这里是错误的选择,这意味着用户只能为一个广告添加书签,并且广告只能由一个用户加入书签。由于用户应该能够为多个广告添加书签,并且广告应该被许多用户添加为书签,因此您需要具有ManyToMany关系。
如果您使用数据库,您想创建映射表书签并没有错。但是,您不需要在Doctrine中将其创建为实体。您可以在“用户”中的“书签”关联中添加广告,以显示已添加书签的广告,反之亦然:
用户实体:
/**
* @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;
这会向用户添加书签,并会在persist
和flush
后立即存储。为了更加轻松,您可以定义remover
和adder
:
使用陈述:
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)));
始终建议在toMany关系中定义adder
和remover
,因为许多Doctrine组件都需要它们,例如非常有用的DoctrineObject,DoctrineModule用于Zend 2的水化器