【问题标题】:PHP Doctrine : Test if an object is in an ArrayCollectionPHP Doctrine : 测试对象是否在 ArrayCollection 中
【发布时间】:2016-06-08 02:24:28
【问题描述】:

我正在尝试使用方法 ArrayCollection::contains 来查找对象是否已经在我的集合中,但是当我这样做时:

//My ArrayCollection
$lesRoles = $drt->getDrtApplication()->getRoles();
$leRole = $lesRoles->first();
echo "Property appNom : ".$leRole->getRleApplication()->getAppNom()."// Property appRole : ".$leRole->getRleId()." <br>";


$role = new \Casgaya\Role(2,$drt->getDrtApplication());
echo "Property appNom : ".$role->getRleApplication()->getAppNom()."// Property appRole : ".$role->getRleId()." <br>";

var_dump($lesRoles->contains($role));

结果是:
属性 appNom : CORA// 属性 appRole : 2
属性 appNom : CORA// 属性 appRole : 2
布尔(假)

由于 appNom 和 rleId 是实体 Role 拥有的仅有的两个属性,因此我希望它会返回 true。

编辑新的测试用例:

echo "Test object role :  <br>";
var_dump($lesRoles==$role);
echo"<br>";
echo "Test integer property rleID from object role :  <br>";
var_dump($role->getRleId() == $leRole->getRleId());
echo"<br>";
echo "Test Application object property RleApplication from object role : <br> ";
var_dump($role->getRleApplication() == $leRole->getRleApplication());

结果是:

属性 appNom : CORA// 属性 appRole : 2
属性 appNom : CORA// 属性 appRole : 2
测试对象角色 :
bool(false)
从对象角色测试整数属性 rleID:
bool(true)
从对象角色测试应用程序对象属性 RleApplication :
布尔(真)

请注意,当我测试两个属性的相等性时,它们都为真。但是当我测试整个对象的相等性时,它是错误的。

所以问题不再是关于 ArrayCollection::contains 的问题,而是:
在相等的情况下,两个学说实体的比较标准是什么?

【问题讨论】:

  • 为什么你认为它应该返回true?你最好创建一个简单的 ArrayCollection,放一个你想要的角色,然后检查集合是否包含这个角色(如果你想检查它是如何工作的)。看起来您刚刚创建的 $role(角色的新实例)无法在集合中 - 只是因为它刚刚被实例化。
  • 这只是一个测试用例,我创建了一个我知道已经在arrayCollection 中的对象。而且它们都具有完全相同的属性。
  • 你刚刚创建了它,你希望它在你刚刚初始化的集合中。

标签: php doctrine-orm contains equality arraycollection


【解决方案1】:

我有同样的问题:

$Xrepository->removeX($x);
$x->getY()->removeXRelation($x);

removeXXXRelation() 中,我测试了与ArrayCollection-&gt;contains() 的关系是否存在
这个contains() 会失败

经过 2 小时的调试和尝试解决方案是这样的

$x->getY()->removeXRelation($x);
$Xrepository->removeX($x);

只需翻转删除调用。

如您所见,Doctrine 正在对物体施展魔法。
这个魔法从 remove 调用开始。
一位同事告诉我有关休眠对象生命周期状态的信息,它解析为:
不再持久化、持久化和不再持久化
由于生命周期状态更改,您的对象可能会生成两次,从而使 contains() 变为 false(包含检查对象身份)
这是我的理论(如果我错了请告诉我)

【讨论】:

    【解决方案2】:

    我自己找到了解决方案,这里是为有同样问题的人准备的:

    我使用方法 ArrayCollection::exists 而不是包含,所以我可以指定对象之间的相等性应该建立在哪些标准上:

    就我而言:

    $result = $lesRoles->exists(function($key,$element) use ($role) 
    {
        return ($element->getRleApplication() == $role->getRleApplication() && $role->getRleId() == $element->getRleId());
    });
    

    请注意,这里的 $key 和 $element 是从集合中测试的当前对象。

    【讨论】:

      【解决方案3】:

      包含(混合$元素) 检查给定元素是否包含在集合中。只比较元素值,不比较键。两个元素的比较是严格的,这意味着不仅值必须匹配,类型也必须匹配。 对于对象,这意味着引用相等。

      来源: http://www.doctrine-project.org/api/common/2.1/class-Doctrine.Common.Collections.ArrayCollection.html

      如果你想检查某个角色是否包含在集合中,你可以通过 Doctrine 检索它 - 它会返回相同的对象,因为 Doctrine 通常不会获取已经通过另一个查询获取的实体。

      【讨论】:

      • 谢谢你,你帮助我专注于真正的问题。不是方法包含来自 ArrayCollection,而是如何建立两个学说实体之间的相等性。
      • 我认为在测试的情况下,您可以自己比较属性或编写一些辅助方法。就 Doctrine 而言,这是一种魔法。例如,您可以获取一个对象,然后获取一些包含该对象的集合,并且 Doctrine 应该使用相同的实例 - 引用相等。如果可能,Doctrine 会使用内存中存在的对象而不是 hydrating new。检查它的简单方法是转储具有双向关系的实体:子实体将包含对父实体的引用。
      猜你喜欢
      • 2012-11-05
      • 2013-12-28
      • 1970-01-01
      • 2014-10-11
      • 1970-01-01
      • 2010-09-22
      • 2012-04-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多