DDC-1635: Single Table Inheritance and a composite key gives the wrong entity when using the IdentityMap #2052

Closed
opened 2026-01-22 13:38:53 +01:00 by admin · 6 comments
Owner

Originally created by @doctrinebot on GitHub (Feb 6, 2012).

Originally assigned to: @beberlei on GitHub.

Jira issue originally created by user h-andreas:

Given the following data, a single table inheritance with 'type' being the discriminator column and a composite key of (type, key, foreign):

||type||key||foreign||
|type-1|key-1|xyz|
|type-2|key-1|xyz|

As Doctrine only takes the columns 'key' and 'foreign' into the composite key, it gives me an instance of the class being mapped to 'type-1' when wanting to select an instance of 'type-2' with key=key-1 && foreign=xyz. BUT this only occurs when i already fetched the instance mapped to type-1 with the same values.

Originally created by @doctrinebot on GitHub (Feb 6, 2012). Originally assigned to: @beberlei on GitHub. Jira issue originally created by user h-andreas: Given the following data, a single table inheritance with 'type' being the discriminator column and a composite key of (type, key, foreign): ||type||key||foreign|| |type-1|key-1|xyz| |type-2|key-1|xyz| As Doctrine only takes the columns 'key' and 'foreign' into the composite key, it gives me an instance of the class being mapped to 'type-1' when wanting to select an instance of 'type-2' with key=key-1 && foreign=xyz. BUT this only occurs when i already fetched the instance mapped to type-1 with the same values.
admin added the Bug label 2026-01-22 13:38:53 +01:00
admin closed this issue 2026-01-22 13:38:53 +01:00
Author
Owner

@doctrinebot commented on GitHub (Feb 10, 2012):

Comment created by @beberlei:

The type can never be part of the primary key, how did you even map that? can you post details?

@doctrinebot commented on GitHub (Feb 10, 2012): Comment created by @beberlei: The type can never be part of the primary key, how did you even map that? can you post details?
Author
Owner

@doctrinebot commented on GitHub (Feb 14, 2012):

Comment created by h-andreas:

I did not specified type as being part of the primary key ... for obvious reasons. I didnt even thought of it being necessary as this is the only time we are using single table inheritance.

This is an abstracted version of our domain model:

CREATE TABLE `users` (
    `id` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT,
    `mail` VARCHAR(255) NULL DEFAULT NULL,
    `passwd` VARCHAR(255) NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB;

CREATE TABLE `tasks` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `f_user` MEDIUMINT(8) UNSIGNED NULL DEFAULT NULL,
    `priority` SMALLINT(5) UNSIGNED NOT NULL,
    `some*other*column` VARCHAR(255) NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    CONSTRAINT `fk*tasks_user` FOREIGN KEY (`f*user`) REFERENCES `users` (`id`) ON UPDATE CASCADE ON DELETE SET NULL
) ENGINE=InnoDB;

CREATE TABLE `attributes` (
    `key` VARCHAR(50) NOT NULL,
    `name` VARCHAR(255) NOT NULL,
    PRIMARY KEY (`key`)
) ENGINE=InnoDB;

CREATE TABLE `attributes_rel` (
    `type` ENUM('task','user') NOT NULL,
    `foreign_id` BIGINT(20) UNSIGNED NOT NULL,
    `f_attribute` VARCHAR(50) NOT NULL,
    `value_int` BIGINT(20) UNSIGNED NULL DEFAULT NULL,
    `value_date` DATETIME NULL DEFAULT NULL,
    `value_text` TEXT NULL,
    PRIMARY KEY (`type`, `foreign*id`, `f*attribute`),
    CONSTRAINT `fk*attributes_rel_attribute` FOREIGN KEY (`f*attribute`) REFERENCES `attributes` (`key`) ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB;

INSERT INTO `attributes` (`key`, `name`) VALUES
  ('description', 'description');

INSERT INTO `users` (`id`, `mail`, `passwd`) VALUES
  (1, 'abc@def.xyz', 'e10adc3949ba59abbe56e057f20f883e');

INSERT INTO `tasks` (`id`, `f*user`, `priority`, `some_other*column`) VALUES
  (1, 1, 1, 'nothing in here');

INSERT INTO `attributes*rel` (`type`, `foreign_id`, `f_attribute`, `value_int`, `value_date`, `value*text`) VALUES
  ('task', 1, 'description', NULL, NULL, 'catchy description for a task'),
  ('user', 1, 'description', NULL, NULL, 'catchy description for a user');
// definition wihin task model
/****
 * @var \Doctrine\Common\Collections\ArrayCollection
 *
 * @OneToMany(targetEntity="TaskAttribute", mappedBy="foreign")
 * @JoinColumn(name="foreign", referencedColumnName="id")
 */
protected $attributes;

// definition wihin user model
/****
 * @var \Doctrine\Common\Collections\ArrayCollection
 *
 * @OneToMany(targetEntity="UserAttribute", mappedBy="foreign")
 * @JoinColumn(name="foreign", referencedColumnName="id")
 */
protected $attributes;

When calling $em->find('Task', 1)->getAttributes() and then doing $em->find('User', 1)->getAttributes() it gives me an instance of TaskAttribute for the user instead of a fresh UserAttribute.

@doctrinebot commented on GitHub (Feb 14, 2012): Comment created by h-andreas: I did not specified type as being part of the primary key ... for obvious reasons. I didnt even thought of it being necessary as this is the only time we are using single table inheritance. This is an abstracted version of our domain model: ``` CREATE TABLE `users` ( `id` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT, `mail` VARCHAR(255) NULL DEFAULT NULL, `passwd` VARCHAR(255) NULL DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB; CREATE TABLE `tasks` ( `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `f_user` MEDIUMINT(8) UNSIGNED NULL DEFAULT NULL, `priority` SMALLINT(5) UNSIGNED NOT NULL, `some*other*column` VARCHAR(255) NULL DEFAULT NULL, PRIMARY KEY (`id`), CONSTRAINT `fk*tasks_user` FOREIGN KEY (`f*user`) REFERENCES `users` (`id`) ON UPDATE CASCADE ON DELETE SET NULL ) ENGINE=InnoDB; CREATE TABLE `attributes` ( `key` VARCHAR(50) NOT NULL, `name` VARCHAR(255) NOT NULL, PRIMARY KEY (`key`) ) ENGINE=InnoDB; CREATE TABLE `attributes_rel` ( `type` ENUM('task','user') NOT NULL, `foreign_id` BIGINT(20) UNSIGNED NOT NULL, `f_attribute` VARCHAR(50) NOT NULL, `value_int` BIGINT(20) UNSIGNED NULL DEFAULT NULL, `value_date` DATETIME NULL DEFAULT NULL, `value_text` TEXT NULL, PRIMARY KEY (`type`, `foreign*id`, `f*attribute`), CONSTRAINT `fk*attributes_rel_attribute` FOREIGN KEY (`f*attribute`) REFERENCES `attributes` (`key`) ON UPDATE CASCADE ON DELETE CASCADE ) ENGINE=InnoDB; INSERT INTO `attributes` (`key`, `name`) VALUES ('description', 'description'); INSERT INTO `users` (`id`, `mail`, `passwd`) VALUES (1, 'abc@def.xyz', 'e10adc3949ba59abbe56e057f20f883e'); INSERT INTO `tasks` (`id`, `f*user`, `priority`, `some_other*column`) VALUES (1, 1, 1, 'nothing in here'); INSERT INTO `attributes*rel` (`type`, `foreign_id`, `f_attribute`, `value_int`, `value_date`, `value*text`) VALUES ('task', 1, 'description', NULL, NULL, 'catchy description for a task'), ('user', 1, 'description', NULL, NULL, 'catchy description for a user'); ``` ``` // definition wihin task model /**** * @var \Doctrine\Common\Collections\ArrayCollection * * @OneToMany(targetEntity="TaskAttribute", mappedBy="foreign") * @JoinColumn(name="foreign", referencedColumnName="id") */ protected $attributes; // definition wihin user model /**** * @var \Doctrine\Common\Collections\ArrayCollection * * @OneToMany(targetEntity="UserAttribute", mappedBy="foreign") * @JoinColumn(name="foreign", referencedColumnName="id") */ protected $attributes; ``` When calling `$em->find('Task', 1)->getAttributes()` and then doing `$em->find('User', 1)->getAttributes()` it gives me an instance of TaskAttribute for the user instead of a fresh UserAttribute.
Author
Owner

@doctrinebot commented on GitHub (Feb 18, 2012):

Comment created by @beberlei:

To have type part of the primary key you have to map it as field. Discrimnator columns can never be part of the PK for doctrine, even if they are in the database.

You can change your domain model to something like

class Attribute
{
   /*** @Id @Column(type="integer") **/
   public $type;
   /*** @Id @ManyToOne(target="Foreign") **/
   public $foreign;
   /*** @id @Column(type="string") **/
   public $key;
}
@doctrinebot commented on GitHub (Feb 18, 2012): Comment created by @beberlei: To have type part of the primary key you have to map it as field. Discrimnator columns can never be part of the PK for doctrine, even if they are in the database. You can change your domain model to something like ``` class Attribute { /*** @Id @Column(type="integer") **/ public $type; /*** @Id @ManyToOne(target="Foreign") **/ public $foreign; /*** @id @Column(type="string") **/ public $key; } ```
Author
Owner

@doctrinebot commented on GitHub (Feb 18, 2012):

Issue was closed with resolution "Invalid"

@doctrinebot commented on GitHub (Feb 18, 2012): Issue was closed with resolution "Invalid"
Author
Owner

@doctrinebot commented on GitHub (Feb 20, 2012):

Comment created by h-andreas:

But then i cant use table inheritance.

@doctrinebot commented on GitHub (Feb 20, 2012): Comment created by h-andreas: But then i cant use table inheritance.
Author
Owner

@doctrinebot commented on GitHub (Feb 20, 2012):

Comment created by @beberlei:

Yes, you can't in your scenario, its just not supported with the discriminator column in it.

@doctrinebot commented on GitHub (Feb 20, 2012): Comment created by @beberlei: Yes, you can't in your scenario, its just not supported with the discriminator column in it.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#2052