Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Composite primary key & association entities as keys improvements #1113

Closed
wants to merge 13 commits into from

Conversation

goetas
Copy link
Member

@goetas goetas commented Aug 18, 2014

Hi!
I tried to implement the matching of entities that uses composite primary keys...

Any suggestion?

BC changes here https://github.com/doctrine/doctrine2/pull/1113/files#diff-c18001a2ca9928743b1e99854ffad33bL1611 (protected method makred as private and changed return type..)

@doctrinebot
Copy link

Hello,

thank you for creating this pull request. I have automatically opened an issue
on our Jira Bug Tracker for you. See the issue link:

http://www.doctrine-project.org/jira/browse/DDC-3258

We use Jira to track the state of pull requests and the versions they got
included in.

@Ocramius
Copy link
Member

@goetas can you add a functional test that shows how this API is supposed to work at repository or collection level?

*
* @return ORMException
*/
public static function cantUseInOperatorOnComposteKeys()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo. Missing i

@goetas
Copy link
Member Author

goetas commented Aug 19, 2014

@stof Thanks for reviewing my code

@goetas
Copy link
Member Author

goetas commented Aug 19, 2014

It would be nice to have:

//Admin1 is an entity with a composite key (country+code)
//Admin1AlternativeNames is an entity with a simple key (id) + Admin1 as association

$compositeEntity = $em->getRepository('Admin1')
   ->findOneBy(array('country' => 'IT', 'id' => 1));

$dql = $em->getRepository('Admin1AlternativeNames')
   ->createQueryBuilder('n')
   ->andWhere("n.admin1 = :admin1")
   ->setParameter("admin1", $compositeEntity);

but at the moment seems to be complicated for me... :-(

@goetas
Copy link
Member Author

goetas commented Aug 19, 2014

I think that postgres failure is not related to my changes...

@deeky666
Copy link
Member

@goetas no I think this is related to the recent merge of doctrine/dbal#444

@goetas goetas mentioned this pull request Aug 19, 2014
@guilhermeblanco
Copy link
Member

@goetas there's no BC break, since we do not allow custom persisters (yet)

@goetas
Copy link
Member Author

goetas commented Aug 19, 2014

@guilhermeblanco good to know!

@goetas goetas changed the title Added support for composite primary key on findBy methods and Criteria [WIP] Composite primary key & association entities as keys improvements Aug 22, 2014
@@ -413,6 +422,7 @@ public function loadAll(array $criteria = array(), array $orderBy = null, $limit
$rsm = $this->getResultSetMapping();
$querykey = new QueryCacheKey($hash, 0, Cache::MODE_NORMAL);
$queryCache = $this->cache->getQueryCache($this->regionName);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

white line.. i will fix it :-(

@goetas goetas changed the title [WIP] Composite primary key & association entities as keys improvements Composite primary key & association entities as keys improvements Aug 22, 2014
@goetas
Copy link
Member Author

goetas commented Aug 22, 2014

Hi everybody! Now it should be complete!

@@ -232,6 +233,14 @@ public function storeEntityCache($entity, EntityCacheKey $key)
$class = $this->metadataFactory->getMetadataFor($className);
}

if ($class->containsForeignIdentifier) {
foreach ($class->associationMappings as $name => $assoc) {
if (isset($assoc['id']) && $assoc['id'] && !isset($assoc['cache'])) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use ! empty($assoc['id']) instead of isset($assoc['id']) && $assoc['id']?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to know! I will do that!

*
* @param string $field
* @param mixed $value
*
* @return integer
* @return array
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would document it as integer[] which explains what type is inside the array too

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getTypes will return strings and integers... integers will be only when $value is an array

@goetas
Copy link
Member Author

goetas commented Sep 1, 2014

News on this?

*/
public static function cantUseInOperatorOnCompositeKeys()
{
return new self("Can't use IN operator on entities that have composte keys.");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo on "composite" word

@goetas
Copy link
Member Author

goetas commented Oct 22, 2014

@Ocramius I can try to adapt it, but the current implementation of IdentifierFlattener has some lacks...

  • It does not work with composite entities (see here)
  • To make it work well, IdentifierFlattener::flattenIdentifier() has to become recursive, while my implementation does not need recursion since it has access to UoW::$entityIdentifiers hash.
  • The order of $id is very important to get the right flat identifier, and the current implementation relies on it. My implementation relies on ClassMetadata::$identifier property which is more secure to be always correct.
  • This is the most important piece of code where IdentifierFlattener should be used, but at the moment is not used.
  • This is correct only if data comes from second level cache.

@Ocramius
Copy link
Member

It does not work with composite entities (see here)

This is something that I discussed in the PR that introduced it ( #1143 ): needs improvement

To make it work well, IdentifierFlattener::flattenIdentifier() has to become recursive, while my implementation does not need recursion since it has access to UoW::$entityIdentifiers hash.

Making it recursive seems acceptable to me here: what's the problem with that? We could also make the entity identifiers accessible to it.

The order of $id is very important to get the right flat identifier, and the current implementation relies on it. My implementation relies on ClassMetadata::$identifier property which is more secure to be always correct.

Should be improved also in the IdentifierFlattener implementation then, and we get rid of duplication of this hidden rule, plus we can test specifically the order here.

This is the most important piece of code where IdentifierFlattener should be used, but at the moment is not used.

It was just introduced, so it is obviously not yet used across the system :-)

This is correct only if data comes from second level cache.

Can you clarify on this? What would be a failure case?

@Ocramius Ocramius self-assigned this Oct 22, 2014
@@ -2639,10 +2625,18 @@ public function createEntity($className, array $data, &$hints = array())

if ($joinColumnValue !== null) {
if ($targetClass->containsForeignIdentifier) {
if ($joinColumnValue instanceof AssociationCacheEntry) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm really not proud of this. Ideas?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FabioBatSilva maybe got ideas?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ocramius It was my mistake... fixed with goetas@268426a
/cc @FabioBatSilva

@goetas goetas changed the title [WIP] Composite primary key & association entities as keys improvements Composite primary key & association entities as keys improvements Jan 29, 2015
@goetas
Copy link
Member Author

goetas commented Jan 29, 2015

Ok, now looks better

@@ -335,7 +335,11 @@ protected function fetchVersionValue($versionedClass, $id)
. ' FROM ' . $tableName
. ' WHERE ' . implode(' = ? AND ', $identifier) . ' = ?';

$flatId = $this->identifierFlattener->flattenIdentifier($versionedClass, (array) $id);
if (!is_array($id)) {
$id = array($this->class->identifier[0] => $id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@goetas this is very naive, and assumes a single column identifier.

What if I try to fetch the version of an entity with a composite identity?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may also avoid calling this method with a mixed $id, and change its signature to enforce array

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the assignDefaultVersionValue signature, simplified a lot! Good advice! :-D

@goetas
Copy link
Member Author

goetas commented Feb 2, 2015

Now I'm more satisfied with the pull request status!

@Ocramius
Copy link
Member

Manually merged after a rebase at f908974

@Ocramius
Copy link
Member

Thanks @goetas, as usual nice work :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants