From a592dc116d0b7d37357c0bc7241ba89670fff321 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sat, 5 Feb 2011 18:01:10 +0100 Subject: [PATCH] First part of a tutorial on composite primary keys and identity through foreign entities. --- en/index.rst | 1 + en/tutorials/composite-primary-keys.rst | 211 ++++++++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 en/tutorials/composite-primary-keys.rst diff --git a/en/index.rst b/en/index.rst index f689e552a..4bfc72693 100644 --- a/en/index.rst +++ b/en/index.rst @@ -44,6 +44,7 @@ Tutorials tutorials/getting-started-xml-edition tutorials/working-with-indexed-associations tutorials/extra-lazy-associations + tutorials/composite-primary-keys Cookbook diff --git a/en/tutorials/composite-primary-keys.rst b/en/tutorials/composite-primary-keys.rst new file mode 100644 index 000000000..8048fbb78 --- /dev/null +++ b/en/tutorials/composite-primary-keys.rst @@ -0,0 +1,211 @@ +Composite Primary Keys +====================== + +Doctrine 2 supports composite primary keys natively. Composite keys are a very powerful relational database concept +and we took good care to make sure Doctrine 2 supports as many of the composite primary key use-cases. +For Doctrine 2.0 composite keys of primitive data-types are supported, for Doctrine 2.1 even foreign keys as +primary keys are supported. + +This tutorial shows how the semantics of composite primary keys work and how they map to the database. + +General Considerations +~~~~~~~~~~~~~~~~~~~~~~ + +Every entity with a composite key cannot use an id generator other than "ASSIGNED". That means +the ID fields have to have their values set before you call ``EntityManager#persist($entity)``. + +Primitive Types only +~~~~~~~~~~~~~~~~~~~~ + +Even in version 2.0 you can have composite keys as long as they only consist of the primative types +``integer`` and ``string``. Suppose you want to create a database of cars and use the model-name +and year of production as primary keys: + +.. configuration-block:: + + .. code-block:: php + + name = $name; + $this->year = $year; + } + + public function getModelName() + { + return $this->name; + } + + public function getYearOfProduction() + { + return $this->year; + } + } + + .. code-block:: xml + + + + + + + + + + + .. code-block:: yaml + + VehicleCatalogue\Model\Car: + type: entity + id: + name: + type: string + year: + type: integer + +Now you can use this entity: + +.. code-block:: php + + persist($car); + $em->flush(); + +And for querying you can use arrays to both DQL and EntityRepositories: + +.. code-block:: php + + find("VehicleCatalogue\Model\Car", array("name" => "Audi A8", "year" => 2010)); + + $dql = "SELECT c FROM VehicleCatalogue\Model\Car c WHERE c.id = ?1"; + $audi = $em->createQuery($dql) + ->setParameter(1, array("name" => "Audi A8", "year" => 2010)) + ->getSingleResult(); + +You can also use this entity in associations. Doctrine will then generate two foreign keys one for ``name`` +and to ``year`` to the related entities. + +.. note:: + + This example shows how you can nicely solve the requirement for exisiting + values before ``EntityManager#persist()``: By adding them as mandatory values for the constructor. + +Identity through foreign Entities +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + + Identity through foreign entities is only supported with Doctrine 2.1 + +There are tons of use-cases where the identity of an Entity should be determined by the entity +of one or many parent entities. + +- Dynamic Attributes of an Entity (for example Article). Each Article has many + attributes with primary key "article_id" and "attribute_name". +- Address object of a Person, the primary key of the adress is "user_id". This is not a case of a composite primary + key, but the identity is derived through a foreign entity and a foreign key. +- Join Tables with metadata can be modelled as Entity, for example connections between two articles + with a little description and a score. + +The semantics of mapping identity through foreign entities are easy: + +- Only allowed on Many-To-One or One-To-One associations. +- Plug an ``@Id`` annotation onto every assocation. +- Set an attribute ``association-key`` with the field name of the association in XML. +- Set a key ``associationKey:`` with the field name of the association in YAML. + +Use-Case 1: Dynamic Attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We keep up the example of an Article with arbitrary attributes, the mapping looks like this: + +.. code-block:: php + + attributes[$name] = new ArticleAttribute($name, $value, $this); + } + } + + /** + * @Entity + */ + class ArticleAttribute + { + /** @Id @ManyToOne(targetEntity="Article", inversedBy="attributes") */ + private $article; + + /** @Id @Column(type="string") */ + private $attribute; + + /** @Column(type="string") */ + private $value; + + public function __construct($name, $value, $article) + { + $this->attribute = $name; + $this->value = $value; + $this->article = $article; + } + } + + +Use-Case 2: Simple Derived Identity +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +TODO + +Use-Case 3: Join-Table with Metadata +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +TODO + +Performance Considerations +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +TODO \ No newline at end of file