我有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;
这将为用户添加一个书签,并将在您完成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)));
总是建议在许多关系中定义adder
和remover
,因为许多Doctrine组件将需要它们,例如非常有用的DoctrineObject, DoctrineModule在Zend 2中使用的一个水合器