Details
-
Type:
Bug
-
Status:
Resolved
-
Priority:
Major
-
Resolution: Invalid
-
Affects Version/s: Git Master
-
Fix Version/s: None
-
Component/s: ORM
-
Security Level: All
-
Labels:None
Description
I have this entities:
class User{
/**
* ...
*/
protected $id;
/**
* @ManyToOne(targetEntity="Phone")
* @JoinColumn(name="address_id", referencedColumnName="id")
*/
protected $phone;
}
class Phone{
/**
* ...
*/
protected $id;
}
when run this query:
$phone = new Phone(); $dql = $em->createQueryBuilder(); $dql->from("User", "u"); $dql->andWhere("u.phone = :phone"); $dql->setParameter("phone", $phone); dql->getQuery()->getResult();
i get the exception: Binding entities to query parameters only allowed for entities that have an identifier.
the expected query is:
SELECT * FROM user WHERE phone_id = NULL;
the involved ORM component is AbstractQuery::convertObjectParameterToScalarValue
changing this method, form
protected function convertObjectParameterToScalarValue($value) { $class = $this->_em->getClassMetadata(get_class($value)); if ($class->isIdentifierComposite) { throw new \InvalidArgumentException( "Binding an entity with a composite primary key to a query is not supported. " . "You should split the parameter into the explicit fields and bind them seperately." ); } $values = ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED) ? $this->_em->getUnitOfWork()->getEntityIdentifier($value) : $class->getIdentifierValues($value); $value = $values[$class->getSingleIdentifierFieldName()]; if ( ! $value) { throw new \InvalidArgumentException( "Binding entities to query parameters only allowed for entities that have an identifier." ); } return $value; }
to
protected function convertObjectParameterToScalarValue($value) { $class = $this->_em->getClassMetadata(get_class($value)); if ($class->isIdentifierComposite) { throw new \InvalidArgumentException( "Binding an entity with a composite primary key to a query is not supported. " . "You should split the parameter into the explicit fields and bind them seperately." ); } $state = $this->_em->getUnitOfWork()->getEntityState($value); $values = ($state === UnitOfWork::STATE_MANAGED) ? $this->_em->getUnitOfWork()->getEntityIdentifier($value) : $class->getIdentifierValues($value); $value = $values[$class->getSingleIdentifierFieldName()]; if ( ! $value && $state !== UnitOfWork::STATE_NEW) { throw new \InvalidArgumentException( "Binding entities to query parameters only allowed for entities that have an identifier." ); } return $value; }
.
the modified method check if the 'phone' entity state is new, and if it is true return null.
Returning null is wrong here. If you query for users related to your new phone object, it is not the same than querying for users without a phone (and btw, it would break in your database as u.phone_id = NULL will not be valid in SQL)