如何在实体中执行查询?
namespace Entities\Members;
/**
* @Entity(repositoryClass="\Entities\Member\MembersRepository")
* @Table(name="Members")
* @HasLifecycleCallbacks
*/
class Members extends \Entities\AbstractEntity
{
/**
* @Id @Column(name="id", type="bigint",length=15)
* @GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @Column(name="userid", type="bigint", length=26, nullable=true)
*/
protected $userid;
/**
* @Column(name="fname", type="string", length=255,nullable=true)
*/
protected $fname;
/**
* @OneToMany(targetEntity="\Entities\Users\Wall", mappedBy="entry", cascade={"persist"})
*/
protected $commententries;
public function __construct()
{
$this->commententries = new \Doctrine\Common\Collections\ArrayCollection();
}
}
示例我希望在此实体中有一个名为filter()
的函数
我希望能够过滤commententries
集合。它应该返回一个具有特定条件id=1
的集合。基本上它应该过滤从连接查询收到的数据。
这样的事情:
$this->commententries->findBy(array('id' => 1));
但显然这不起作用。
答案 0 :(得分:21)
你的ArrayCollection已经实现了一个filter()方法,你需要传递一个Closure来使它工作你的实体(这里是commentEntries)。
$idsToFilter = array(1,2,3,4);
$member->getComments()->filter(
function($entry) use ($idsToFilter) {
if (in_array($entry->getId(), $idsToFilter)) {
return true;
}
return false;
}
);
(未经测试)
请注意,此类方法将对您的所有评论进行迭代和急切加载,因此,如果用户有很多,则可能是一个很大的瓶颈;
在大多数情况下,您希望使用自定义存储库,您可以在其中放置此类逻辑。
正如timdev建议的那样,您可以创建一个MemberService,它将通过了解EntityManager来包装此类调用。
将实体与Peristance Layer分开是对Doctrine 1的重大改进,你不应该违反这条规则。
答案 1 :(得分:12)
一般来说,你不应该这样做。
根据经验,实体不应该直接了解实体管理者(或通过某些中间对象)。
这样做的原因主要是可测试性,但根据我的经验,它有助于以其他方式保持组织。
我会通过设计一个处理查找的服务类来实现它。你的控制器(或其他)会像这样驱动它:
<?php
// create a new service, injecting the entitymanager. if you later wanted
// to start caching some things, you might inject a cache driver as well.
$member = $em->find('Member',$member_id); //get a member, some how.
$svc = new MemberService($em);
$favoriteCommentaries = $svc->getFavoriteCommentaries($member);
正如我在评论中提示的那样,如果您稍后决定要添加缓存(例如,通过memcached)以避免频繁查找,那么您可以在此服务类附近或此服务中执行此操作。这使您的实体保持简洁,易于测试。由于您在构造时将实体管理器注入服务,因此可以根据需要进行模拟。
getFavoriteCommentaries()可以使用各种实现。一个微不足道的是将它代理到Member :: getFavoriteCommentaries(),它实际上会加载所有内容,然后过滤掉“最喜欢的”。这可能不会特别好地扩展,因此您可以通过使用EM来获取所需的数据来改进它。
答案 2 :(得分:5)
使用自定义存储库进行查询
您不应该在您的实体中编写查询,但是您应该使用存储库。这也在学说文档 7.8.8 Custom Repositories 中进行了解释。它允许您在中心位置构建自定义查询,并保持实体定义清洁。
使用条件过滤集合:
但是,如果您想使用get
方法在集合内部进行过滤,则可以使用Criteria
。您可以在Doctrine文档 8.8 Filtering collections 中了解如何使用Criteria
。像你想要的那样过滤会看起来像这样:
在实体类的顶部声明Criteria
类
use Doctrine\Common\Collections\Criteria
在您的getCommentEntries
方法中,使用该类进行过滤:
public function getCommentEntries()
{
$criteria = Criteria::create()
->where(Criteria::expr()->eq('id', 1));
$filteredCommentEntries = $this->commententries->matching($criteria);
return $filteredCommentEntries;
}
答案 3 :(得分:1)
您的问题很难理解,请尝试着解您将来如何构建问题。例如,你说“返回相同的结果”,但“过滤”,这可能意味着什么。你想使用相同的结果集(为什么你会选择这样做),只是使用array_filter或array_walk来过滤结果,或者你真的想要使用条件连接吗?这是非常模糊的。
无论如何......回答(4次阅读你的问题后)。
$q = $qb->select ( "m","w" )
->from ( "Members", "m" )
->leftJoin( "m.commententries","w",'WITH', 'w.id = :id')
->setParameter ( "id", $id )
->getQuery ();
答案 4 :(得分:1)
我同意“timdev”。您不应该在实体类中定义查询。我定义服务类的方式支持实体是存储库类。例如:User(entity - YourBundle / Entity / User.php)将具有UserRepository(服务类 - YourBundle / Repository / UserRepository.php)。你的“过滤器”方法应该在这里。您只需要在实体类中映射此服务类。在您的控制器中,您始终可以通过其存储库访问“过滤器”。它在Symfony2 book
中详细记录