33:root-project-dir: ../../../../../../..
44:core-project-dir: {root-project-dir}/hibernate-core
55:example-dir-association: {core-project-dir}/src/test/java/org/hibernate/orm/test/associations
6+ :example-dir-any: {core-project-dir}/src/test/java/org/hibernate/orm/test/any
67:extrasdir: extras/associations
78
89Associations describe how two or more entities form a relationship based on a database joining semantics.
@@ -559,7 +560,7 @@ The `@Any` mapping is useful to emulate a unidirectional `@ManyToOne` associatio
559560
560561Because the `@Any` mapping defines a polymorphic association to classes from multiple tables,
561562this association type requires the FK column which provides the associated parent identifier and
562- a metadata information for the associated entity type.
563+ a discriminator which identifies the associated entity type.
563564
564565[NOTE]
565566====
@@ -568,16 +569,33 @@ This is not the usual way of mapping polymorphic associations and you should use
568569
569570To map such an association, Hibernate needs to understand 3 things:
570571
571- 1. The column and mapping for the discriminator
572- 2. The column and mapping for the key
573- 3. The mapping between discriminator values and entity classes
572+ 1. The column and mapping for the <<associations-any-discriminator,discriminator>>
573+ 2. The column and mapping for the <<associations-any-key,key>>
574+ 3. The mapping between discriminator values and entity types which may be <<associations-any-explicit-discriminator,explicit>>
575+ <<associations-any-implicit-discriminator,implicit>> or <<associations-any-mixed-discriminator,mixed>>.
576+
577+ For the rest of this discussion, consider the following model which will be the target types for the `@Any` associations:
578+
579+ [[associations-any-target-example]]
580+ .`Payment` class hierarchy
581+ ====
582+ [source, java, indent=0]
583+ ----
584+ include::{example-dir-any}/discriminator/Payment.java[tags=associations-any-example]
585+
586+ include::{example-dir-any}/discriminator/CardPayment.java[tags=associations-any-example]
587+
588+ include::{example-dir-any}/discriminator/CashPayment.java[tags=associations-any-example]
589+
590+ include::{example-dir-any}/discriminator/CheckPayment.java[tags=associations-any-example]
591+ ----
592+ ====
574593
575594
576595[[associations-any-discriminator]]
577596===== The discriminator
578597
579- The discriminator of an any-style association holds the value that indicates which entity is
580- referred to by a row.
598+ The discriminator is the value that indicates which entity is referred to by a row.
581599
582600Its "column" can be specified with either `@Column` or `@Formula`. The mapping type can be influenced by any of:
583601
@@ -601,114 +619,105 @@ type can be influenced by any of:
6016194. `@AnyKeyJdbcTypeCode`
602620
603621
604- [[associations-any-values]]
605- ===== The discriminator value mappings
606622
607- `@AnyDiscriminatorValue` is used to map the discriminator values to the corresponding entity classes
623+ [[associations-any-explicit-discriminator]]
624+ ===== Explicit discriminator mappings
608625
626+ Explicit discriminator mappings are defined using one-or-more `@AnyDiscriminatorValue` annotations. E.g.
609627
610- [[associations-any-property]]
611- ==== Example using @Any mapping
612628
613- For this example, consider the following `Property` class hierarchy:
614-
615- [[associations-any-property-example]]
616- .`Property` class hierarchy
629+ [[associations-any-discriminator-explicit-example]]
630+ .Explicit @AnyDiscriminatorValue annotations
617631====
618632[source, java, indent=0]
619633----
620- include::{example-dir-association}/any/Property.java[tags=associations-any-property-example]
621-
622- include::{example-dir-association}/any/IntegerProperty.java[tags=associations-any-property-example]
623-
624- include::{example-dir-association}/any/StringProperty.java[tags=associations-any-property-example]
634+ include::{example-dir-any}/discriminator/explicit/Order.java[tags=associations-any-explicit-discriminator-example]
625635----
626636====
627637
628- A `PropertyHolder` entity defines an attribute of type `Property`:
638+ Here, we map 2 explicit discriminator value mappings:
639+
640+ 1. `CARD` <-> `CardPayment`
641+ 2. `CHECK` <-> `CheckPayment`
642+
643+ Notice that `CashPayment` is not explicitly mapped. An attempt to use `CashPayment` for this attribute will result
644+ in an exception.
645+
629646
630- [[associations-any-example]]
631- .`@Any` mapping usage
647+ [[associations-any-implicit-discriminator]]
648+ ===== Implicit discriminator mappings
649+
650+ Implicit discriminator mappings define no `@AnyDiscriminatorValue` annotations. E.g.
651+
652+ [[associations-any-discriminator-implicit-example]]
653+ .Implicit @Any discriminator mappings
632654====
633655[source, java, indent=0]
634656----
635- include::{example-dir-association}/any/PropertyHolder.java[tags=associations-any-example]
636- ----
637-
638- [source, SQL, indent=0]
639- ----
640- include::{extrasdir}/associations-any-example.sql[]
657+ include::{example-dir-any}/discriminator/implicit/Order.java[tags=associations-any-implicit-discriminator-example]
641658----
642659====
643660
644- `PropertyHolder#property` can refer to either `StringProperty` or `IntegerProperty` references, as indicated
645- by the associated discriminator according to the `@DiscriminatorValue` annotations.
661+ Here all `Payment` subtypes are allowed. By default Hibernate will use the entity's full-name (which is generally the class's FQN).
646662
647- As you can see, there are two columns used to reference a `Property` instance: `property_id` and `property_type`.
648- The `property_id` is used to match the `id` column of either the `string_property` or `integer_property` tables,
649- while the `property_type` is used to match the `string_property` or the `integer_property` table.
663+ Hibernate also offers a `@AnyDiscriminatorImplicitValues` annotation which allows configuration of how this implicit
664+ mapping works. E.g., to use the entity's short-name instead of the full-name -
650665
651- To see the `@Any` annotation in action, consider the next examples.
652666
653- If we persist an `IntegerProperty` as well as a `StringProperty` entity, and associate
654- the `StringProperty` entity with a `PropertyHolder`,
655- Hibernate will generate the following SQL queries:
656-
657- [[associations-any-persist-example]]
658- .`@Any` mapping persist example
667+ [[associations-any-discriminator-implicit-short-example]]
668+ .Implicit @Any discriminator mappings (short name)
659669====
660670[source, java, indent=0]
661671----
662- include::{example-dir-association}/any/AnyTest .java[tags=associations-any-persist -example]
672+ include::{example-dir-any}/discriminator/implicit/Order .java[tags=associations-any-implicit-discriminator-short -example]
663673----
674+ ====
664675
665- [source, SQL, indent=0]
666- ----
667- include::{extrasdir}/associations-any-persist-example.sql[]
668- ----
676+ [NOTE]
669677====
678+ `@AnyDiscriminatorImplicitValues` also offers the ability to define a custom strategy for determining the
679+ discriminator-value <-> entity-type mapping, but its use is not covered here.
680+ ====
681+
682+
683+ [[associations-any-mixed-discriminator]]
684+ ===== Mixed discriminator mappings
670685
671- When fetching the `PropertyHolder` entity and navigating its `property` association,
672- Hibernate will fetch the associated `StringProperty` entity like this:
686+ A mixed strategy combines `@AnyDiscriminatorValue` and `@AnyDiscriminatorImplicitValues`. Mappings
687+ explicitly defined using `@AnyDiscriminatorValue` take precedence. E.g.
673688
674- [[associations-any-query-example]]
675- .`@Any` mapping query example
689+
690+ [[associations-any-discriminator-mixed-example]]
691+ .Mixed @Any discriminator mappings (short name)
676692====
677693[source, java, indent=0]
678694----
679- include::{example-dir-association}/any/AnyTest.java[tags=associations-any-query-example]
680- ----
681-
682- [source, SQL, indent=0]
683- ----
684- include::{extrasdir}/associations-any-query-example.sql[]
695+ include::{example-dir-any}/discriminator/mixed/Order.java[tags=associations-any-mixed-discriminator-short-example]
685696----
686697====
687698
688699
700+
689701[[associations-any-meta-annotations]]
690702===== Using meta-annotations
691703
692704As mentioned in <<basic-mapping>>, Hibernate's ANY-related annotations can be composed using meta-annotations
693705to re-use ANY mapping details.
694706
695- Looking back at <<associations-any-example>> , we can see how cumbersome it would be to duplicate that
696- information every time `Property ` is mapped in the domain model. This description can also be moved
707+ Given all the details needed to define an ANY mapping , we can see how cumbersome it would be to duplicate that
708+ information every time `Payment ` is mapped in the domain model. This description can also be moved
697709into a single annotation that we can apply in each usage.
698710
699711
700712[[associations-any-composed-example]]
701- .`@Any` mapping usage
713+ .`@Any` mapping with meta-annotation
702714====
703715[source, java, indent=0]
704716----
705- include::{example-dir-association}/any/PropertyHolder2 .java[tags=associations-any-def -example]
717+ include::{example-dir-any}/discriminator/meta/Order .java[tags=associations-any-discriminator-meta -example]
706718----
707719====
708720
709- Though the mapping has been "simplified", the mapping works exactly as shown in <<associations-any-example>>.
710-
711-
712721
713722
714723[[associations-many-to-any]]
@@ -724,16 +733,16 @@ The mapping details are the same between `@Any` and `@ManyToAny` except for:
724733 of just `@JoinColumn`
725734
726735
727- In the following example, the `PropertyRepository ` entity has a collection of `Property` entities .
736+ In the following example, the `Loan ` entity has a collection of `Payments` objects .
728737
729- The `repository_properties` link table holds the associations between `PropertyRepository ` and `Property` entities .
738+ The `loan_payments` table holds the associations between `Loan ` and `Payment` references .
730739
731740[[associations-many-to-any-example]]
732741.`@ManyToAny` mapping usage
733742====
734743[source, java, indent=0]
735744----
736- include::{example-dir-association}/any/PropertyRepository .java[tags=associations-many-to-any-example]
745+ include::{example-dir-any}/discriminator/many/Loan .java[tags=associations-many-to-any-example]
737746----
738747
739748[source, SQL, indent=0]
@@ -742,43 +751,6 @@ include::{extrasdir}/associations-many-to-any-example.sql[]
742751----
743752====
744753
745- To see the `@ManyToAny` annotation in action, consider the next examples.
746-
747- If we persist an `IntegerProperty` as well as a `StringProperty` entity,
748- and associate both of them with a `PropertyRepository` parent entity,
749- Hibernate will generate the following SQL queries:
750-
751- [[associations-many-to-any-persist-example]]
752- .`@ManyToAny` mapping persist example
753- ====
754- [source, java, indent=0]
755- ----
756- include::{example-dir-association}/any/ManyToAnyTest.java[tags=associations-many-to-any-persist-example]
757- ----
758-
759- [source, SQL, indent=0]
760- ----
761- include::{extrasdir}/associations-many-to-any-persist-example.sql[]
762- ----
763- ====
764-
765- When fetching the `PropertyRepository` entity and navigating its `properties` association,
766- Hibernate will fetch the associated `IntegerProperty` and `StringProperty` entities like this:
767-
768- [[associations-many-to-any-query-example]]
769- .`@ManyToAny` mapping query example
770- ====
771- [source, java, indent=0]
772- ----
773- include::{example-dir-association}/any/ManyToAnyTest.java[tags=associations-many-to-any-query-example]
774- ----
775-
776- [source, SQL, indent=0]
777- ----
778- include::{extrasdir}/associations-many-to-any-query-example.sql[]
779- ----
780- ====
781-
782754
783755
784756[[associations-JoinFormula]]
0 commit comments