想象一组提案,每个用户都可以为提案投票或者投票。
所以我有2个模特:
Proposal
,Vote
,与proposal
,user
和opinion
(向上或向下)相关。现在,我想显示所有提案,包括每个提案的额外信息:
这很容易实现,但这意味着每个提案显示4个请求(称为n + 1查询问题)。 我来自Rails世界,可以使用急切加载或一些棘手的查询轻松解决这个问题。但我不能用学说来解决它,需要一些帮助!
第一个解决方案是进行自定义查询:选择所有提案,包括upvotes,downvotes的数量,让当前用户上调或下调。
现在,查询会返回比模型描述的列多4列:count_upvotes
,count_downvotes
,has_user_upvoted
和has_user_downvoted
。
要与学说一起使用,我必须将这些字段添加到我的Proposal
实体。
对我来说,这不是一个好的解决方案,因为它意味着始终使用此查询来避免混蛋模型,其中这些字段可以为空。
第二种解决方案是使视图使用另一个对象。使用参数创建此对象:当前用户。此对象由优化查询创建,并包含以下方法:
getAllProposals()
getUpvotes($a_proposal)
getDownvotes($a_proposal)
hasUserUpvoted($a_proposal)
hasUserDownvoted($a_proposal)
对我而言,被迫为视图优化创建一个对象真的太过分了。
此第三个解决方案使用一个唯一的查询来获取提案,他们的upvotes,downvotes,并检查用户是否已经上升或下调。
它创建了一个新的“扩展”实体,
public function __construct(
Proposal $badgeProposal,
$upvotesCount,
$downvotesCount,
$hasUserUpvoted,
$hasUserDownvoted
) {
对我来说,这是更好的解决方案,但目前这不起作用,因为我不知道如何简单地从SQL行水合一个Proposal(但我几乎没有搜索)。
那么,其他什么解决方案呢?对于学说开发者来说,必须是一个众所周知的问题。
答案 0 :(得分:4)
您是否已经对此进行过实验或只考虑过它?
对我来说,一个简单的fetch="EAGER"
解决了这个问题,导致只有一个查询。使用以下设置
class Proposal {
/**
* @ORM\OneToMany(targetEntity="Vote", mappedBy="proposals", fetch="EAGER")
*/
protected $votes;
}
class Vote {
/**
* @ORM\ManyToOne(targetEntity="Proposal", inversedBy="votes")
* @ORM\JoinColumn(..)
*/
protected $proposal;
/**
* @ORM\ManyToOne(targetEntity="Opinion", inversedBy="votes")
* @ORM\JoinColumn(..)
*/
protected $opinion;
/**
* @ORM\ManyToOne(targetEntity="User", inversedBy="votes")
* @ORM\JoinColumn(..)
*/
protected $user;
}
class Opinion/User {
/**
* @ORM\OneToMany(targetEntity="Vote", mappedBy="proposals")
*/
protected $votes;
}
实际上,我对Proposal
实体进行了更多编辑,添加了以下方法
class Proposal {
public function getCountOpinion($id) {
$count = 0;
foreach ($this->getVotes() as $vote) {
if ($vote->getOpinion()->getId() === $id) {
$count++;
}
}
return $count;
}
public function getUserVote($user) {
foreach ($this->getVotes() as $vote) {
if ($vote->getUser() == $user) {
return $vote;
}
}
return null;
}
}
正如我在开头提到的,这仍然只导致一个查询。但是,您在此处看到了很多for
。如果你对每个提案有很多投票,你可能想要缓存结果(例如,只迭代一次投票,得到所有的countOpinion和userVote)
PS:不要忘记为具有ArrayCollections(OneToMany)的类添加构造函数