PHP学说:测试对象是否在ArrayCollection中

PHP Doctrine : Test if an object is in an ArrayCollection

提问人:Silfers IsNobody 提问时间:2/25/2016 最后编辑:Silfers IsNobody 更新时间:2/11/2020 访问量:9631

问:

我正在尝试使用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
bool(false)

由于 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 from object role


bool(true)



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

因此,问题不再是关于 ArrayCollection::contains,而是:
在相等的情况下,根据什么标准比较两个原则实体?

php doctrine-orm 包含 相等 arraycollection

评论

0赞 Alex 2/25/2016
为什么你认为它应该返回 true?你最好创建简单的 ArrayCollection,把一个你想在那里的角色放在那里,并检查集合是否包含该角色(如果你想检查它是如何工作的)。看起来您刚刚创建$role(角色的新实例)不可能在集合中 - 只是因为它刚刚被实例化。
1赞 Silfers IsNobody 2/25/2016
这只是一个测试用例,我创建了一个我知道已经在 arrayCollection 中的对象。它们都具有完全相同的属性。
0赞 Alex 2/26/2016
您刚刚创建了它,并且希望它位于您一秒钟前初始化的集合中。

答:

3赞 auroree 2/25/2016 #1

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

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

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

评论

0赞 Silfers IsNobody 2/25/2016
谢谢你,你帮助我专注于真正的问题。不是 ArrayCollection 包含的方法,而是两个学说实体之间的相等是如何建立的。
0赞 auroree 2/25/2016
我认为在测试的情况下,您可以自己比较属性或编写一些辅助方法。就教义而言,这是一种魔术。例如,您可以获取一个对象,然后获取包含该对象的一些集合,并且 Doctrine 应该使用相同的实例 - 引用相等。如果可能的话,教义使用内存中存在的对象,而不是补充新的对象。检查它的简单方法是具有双向关系的转储实体:子实体将包含对父实体的引用。
10赞 Silfers IsNobody 2/25/2016 #2

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

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

就我而言:

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

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

1赞 Jannis 2/11/2020 #3

I had a same issue:

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

In I tested if the relation was existent with
This would fail
removeXXXRelation()ArrayCollection->contains()contains()

After 2 hours of debugging and trying around the solution was this

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

Simply flipping the remove calls.

As you can see Doctrine is doing magic with the object.
This magic starts with the remove call.
A colleague told me about hibernate object lifecycle states, which resolve to:
Not-persisted, Persisted, and Not-Persisted Anymore
It is possible that due to lifecycle state changes your object is generated twice, making the go false (contains checks the objects identity)
That's my theory (tell me if I am wrong)
contains()