php Doctrine 2,在实体内部查询

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7064528/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 01:56:19  来源:igfitidea点击:

Doctrine 2, query inside entities

phpfilterdoctrine-ormdoctrine

提问by dean jase

How do I perform queries in an entity?

如何在实体中执行查询?

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();
    }
}

Example I would like to have a function inside this entity called: filter()and I want to be able to filter the commententriescollection. It should return a collection with a certain condition such id=1. Basically it should be filtering the data received from the join query.

示例我想在这个实体中调用一个函数:filter()并且我希望能够过滤commententries集合。它应该返回具有特定条件的集合,例如id=1. 基本上它应该过滤从连接查询收到的数据。

So something like this:

所以像这样:

$this->commententries->findBy(array('id' => 1));

But obviously this does not work.

但显然这行不通。

回答by Boris Guéry

Your ArrayCollection already implements a filter() method, you need to pass a Closure to get it to work your entities (here, the commentEntries).

你的 ArrayCollection 已经实现了一个 filter() 方法,你需要传递一个闭包来让它工作你的实体(这里是 commentEntries)。

$idsToFilter = array(1,2,3,4);

$member->getComments()->filter(
    function($entry) use ($idsToFilter) {
       if (in_array($entry->getId(), $idsToFilter))?{
           return true;
       }

       return false;
    }
); 

(not tested)

(未测试)

Note that such method will iterate and eager loadover all your Comments, so in case where a User has a lot it may be a big bottleneck;

请注意,这种方法将迭代并立即加载您的所有评论,因此如果用户有很多评论,这可能是一个很大的瓶颈;

In most case, you want to use a custom repositories, where you can place such logic.

在大多数情况下,您希望使用自定义存储库,您可以在其中放置此类逻辑。

As timdev suggested, you can create a MemberService which will wrap such call by being aware of the EntityManager.

正如 timdev 所建议的,您可以创建一个 MemberService,它将通过了解 EntityManager 来包装此类调用。

Separating Entities from the Peristance Layer is a big improvement over Doctrine 1, and you should not break that rule.

将实体与持久层分离是对 Doctrine 1 的重大改进,您不应该违反该规则。

回答by timdev

Generally speaking, you shouldn't do this.

一般来说,你不应该这样做。

Entities, as a rule of thumb, should not know about the entitymanager (directly, or via some intermediary object).

根据经验,实体不应该知道实体管理器(直接或通过某些中间对象)。

The reason for this is mostly testability, but in my experience, it helps keeps things organized in other ways.

这样做的原因主要是可测试性,但根据我的经验,它有助于以其他方式组织事物。

I'd approach it by designing a service class that handles the lookups for you. Your controller (or whatever) would drive it like this:

我会通过设计一个为您处理查找的服务类来解决它。你的控制器(或其他任何东西)会像这样驱动它:

<?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);

As I hint in the comment, if you decide later that you want to add caching (via memcached, for instance) to avoid frequent lookups, you'd do that somewhere near or in this service class. This keeps your entities nice and simple, and easily testable. Since you inject your entitymanager into the service at construction-time, you can mock that as needed.

正如我在评论中暗示的那样,如果您稍后决定要添加缓存(例如,通过 memcached)以避免频繁查找,您可以在此服务类附近或中的某个位置执行此操作。这使您的实体保持良好和简单,并且易于测试。由于您在构建时将实体管理器注入到服务中,因此您可以根据需要进行模拟。

getFavoriteCommentaries() could use various implementations. A trivial one would be to proxy it to Member::getFavoriteCommentaries(), which would actually load everything, and then filter out the "favorite" ones. That probably won't scale particularly well, so you could improve it by using the EM to fetch just the data you need.

getFavoriteCommentaries() 可以使用各种实现。一个简单的方法是将它代理到 Member::getFavoriteCommentaries(),它实际上会加载所有内容,然后过滤掉“最喜欢的”。这可能不会特别好地扩展,因此您可以通过使用 EM 仅获取您需要的数据来改进它。

回答by Wilt

Use a custom repository for queries

使用自定义存储库进行查询

You should not write queries in your entities, but you should use a repository for that. This is also explained in the doctrine documentation 7.8.8 Custom Repositories. It will allows you to build your custom queries on a central spot and keeps your entity definitions clean.

您不应在实体中编写查询,但应为此使用存储库。这也在学说文档7.8.8 Custom Repositories中进行了解释。它将允许您在中心位置构建自定义查询并保持您的实体定义干净。

Use criteria to filter collections:

使用条件过滤集合:

But if you want to filter inside your collection in a getmethod you can use Criteria. You can read on how to use Criteriain the Doctrine documentation 8.8 Filtering collections. To filter like you want to do would look something like this:

但是,如果您想以一种get方法在您的集合中进行过滤,则可以使用Criteria. 您可以Criteria在 Doctrine 文档8.8 Filtering collections 中阅读有关如何使用的信息。像你想做的那样过滤看起来像这样:

Declare at the top of your entity class the Criteriaclass

在实体类的顶部声明Criteria

use Doctrine\Common\Collections\Criteria

In your getCommentEntriesmethod use the class to filter:

在您的getCommentEntries方法中使用该类进行过滤:

public function getCommentEntries()
{
    $criteria = Criteria::create()
        ->where(Criteria::expr()->eq('id', 1));

    $filteredCommentEntries = $this->commententries->matching($criteria);

    return $filteredCommentEntries;
}

回答by Layke

Your question was really hard to understand, please try and work on how you structure your questions in the future. For instance, you say "return back the same result" but "filter", which could mean anything. Do you want to use the same result set (why on earth would you ever choose to do that), and just use array_filter or array_walk to filter the results or do you actually want to use a conditional join? It's incredibly ambiguous.

你的问题真的很难理解,请尝试在未来如何组织你的问题。例如,你说“返回相同的结果”但“过滤器”,这可能意味着任何事情。你想使用相同的结果集(你到底为什么会选择这样做),并只使用 array_filter 或 array_walk 来过滤结果,还是你真的想使用条件连接?这是令人难以置信的模棱两可。

Anyway.. answer ( after reading your question 4 times).

无论如何..回答(阅读您的问题4次后)。

$q = $qb->select ( "m","w" )
            ->from ( "Members", "m" )
            ->leftJoin( "m.commententries","w",'WITH', 'w.id = :id')
            ->setParameter ( "id", $id )
            ->getQuery ();

回答by hackintos

I agree with "timdev". You shouldn't define query in your entities class. My way to define a service class support the entities are repository classes. For example: User (entity -- YourBundle/Entity/User.php) will have UserRepository (service class -- YourBundle/Repository/UserRepository.php). Your "filter" method should be in here. You just need to map this service class in your entity class. In your controller, you can always access the "filter" via its repository. It's documented very detail in the Symfony2 book

我同意“timdev”。您不应在实体类中定义查询。我定义服务类的方式支持实体是存储库类。例如:用户(实体 -- YourBundle/Entity/User.php)将拥有 UserRepository(服务类 -- YourBundle/Repository/UserRepository.php)。您的“过滤器”方法应该在这里。您只需要在实体类中映射此服务类。在您的控制器中,您始终可以通过其存储库访问“过滤器”。它在Symfony2 book 中有非常详细的记录