From 1e187d8e6960db7c646f008b5617ec8467ae4ae7 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 23 Nov 2023 07:39:53 -0600 Subject: [PATCH] design doc --- design.adoc | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 design.adoc diff --git a/design.adoc b/design.adoc new file mode 100644 index 0000000..e19696e --- /dev/null +++ b/design.adoc @@ -0,0 +1,250 @@ += Design Considerations + +Design discussions and considerations... + +== Current SecondPass Implementations + +Andrea... +== Binding + +Mainly a look at phases for processing the EntityHierarchy + +=== Phase 1 + +Create, link and register "shells" - + +* PersistentClass + ** super type + ** class name + ** entity name + ** JPA entity name + ** table + ** secondary tables +* MappedSuperclass + ** super type + ** class name +* PrimaryKey + ** table +* Column + ** name + ** value + ** really, almost everything can be eagerly initialized +* Formula + ** expression + ** value +* Property + ** name + ** value +* Table ? + ** schema + ** catalog + ** name + ** primary key +* Join ? + ** schema + ** catalog + ** name + ** primary key + ** foreign key (w/ callback to target pk) +* BasicValue ? + ** table + ** ... - it should be possible to fully initialize BasicValues immediately +* Value (in addition to BasicValue) ? + ** Component + ** ManyToOne + *** referencedEntityName + *** fetchMode + *** table + ** OneToOne + *** referencedEntityName + *** fetchMode + *** table + ** Any + *** table + *** discriminator + ** Array + *** owner + *** table + ** Bag + *** owner + *** table + ** IdentifierBag + *** owner + *** table + ** List + *** owner + *** table + ** Map + *** owner + *** table + ** Set + *** owner + *** table + +=== Phase 2 + +Initialize identifiers, including PrimaryKey. Trigger `PrimaryKey#resolved`. + +=== Phase 3 + +Initialize Property/Value. Trigger `Property#resolved`. + +Initialize collection tables, including `PrimaryKey` and `ForeignKey`. Trigger `PrimaryKey#resolved` and `ForeignKey#resolved`. + + + +== Objects Allowing callbacks + +* `PersistentClass` +* `MappedSuperclass` +* `Component` +* `PrimaryKey` +* `ForeignKey` +* `Property` +* `Table` ? +* `Join` ? +* others ? + + + + + +== Mapping Model Changes (proposed) + +Some of these are nice-to-have. +Some of these are "needed". + +=== Addition of callbacks + +The mapping model is built iteratively, meaning at any point it is unknown if a particular "piece" of the object is available. + +Starting with 7.0 we want to move to a more phase centric, reference-based approach (see <>). +Rather than relying on a heterogeneous set of SecondPasses, this means "targeted" callbacks. +Consider processing a secondary table and needing to build the foreign-key. +It would be much nicer to allow something like: + +```java +final PrimaryKey pk = ...; +pk.whenResolved( resolved -> { + // do stuff with the fully resolved PrimaryKey + // - this might be immediately, if the PrimaryKey is already resolved + // - or cached and executed later when the PrimaryKey is later resolved +} ); +``` + +This is the only "needed" one. +There are other, messier ways to accomplish this, but this would make things so much easier. +And I think this has zero effect on tooling. + + +=== MappedSuperclass + +"Nice" to have... + +At the moment, `MappedSuperclass` is mapped awkwardly into the `PersistentClass` model. + +- `org.hibernate.mapping.PersistentClass#getSuperclass()` +- `org.hibernate.mapping.PersistentClass#getSuperMappedSuperclass()` + +`PersistentClass`:: Models an `@Entity` +* `getSuperclass()` returns the first super IdentifiableType which is an entity. +* `getSuperMappedSuperclass()` returns the direct `MappedSuperclass`, if one. + +`MappedSuperclass`:: Models a `@MappedSuperclass` +* `getSuperMappedSuperclass()` returns the direct `MappedSuperclass`, if one. +* `getSuperPersistentClass()` returns the first super IdentifiableType which is an entity. + +JPA's `IdentifiableType` is the logical super-type for both of these, or between them - both `EntityType` and `MappedSuperclassType` extend from `IdentifiableType` + + +```java +@MappedSuperclass +class RootMappedSuperclass { + ... +} + +@Entity +class RootEntity extends RootMappedSuperclass { + ... +} + +@MappedSuperclass +class DivergentMappedSuperclass extends RootEntity { + ... +} + +@MappedSuperclass +class ThingsMappedSuperclass extends DivergentMappedSuperclass { + ... +} + +@Entity +class Thing1 extends ThingsMappedSuperclass { + ... +} + +@Entity +class Thing2 extends Thing1 { + ... +} +``` + +MappedSuperclass(RootMappedSuperclass):: +superPersistentClass == null +superMappedSuperclass == null + +PersistentClass(RootEntity):: +superclass == null // it's the root entity +superMappedSuperclass == MappedSuperclass(RootMappedSuperclass) + +MappedSuperclass(DivergentMappedSuperclass):: +superPersistentClass == PersistentClass(RootEntity) +superMappedSuperclass == null + +MappedSuperclass(ThingsMappedSuperclass):: +superPersistentClass == PersistentClass(RootEntity) +superMappedSuperclass == MappedSuperclass(ThingsMappedSuperclass) + +PersistentClass(Thing1):: +superclass == PersistentClass(RootEntity) +superMappedSuperclass == MappedSuperclass(ThingsMappedSuperclass) + +PersistentClass(Thing2):: +superclass == PersistentClass(Thing1) +superMappedSuperclass == null + +This would be easier to build (and probably understand) to instead just model this more like JPA : + +MappedSuperclass(RootMappedSuperclass):: +superType == null + +PersistentClass(RootEntity):: +superType == MappedSuperclass(RootMappedSuperclass) + +MappedSuperclass(DivergentMappedSuperclass):: +superType == PersistentClass(RootEntity) + +MappedSuperclass(ThingsMappedSuperclass):: +superType == MappedSuperclass(DivergentMappedSuperclass) + +PersistentClass(Thing1):: +superType == MappedSuperclass(ThingsMappedSuperclass) + +PersistentClass(Thing2):: +superType == PersistentClass(Thing1) + +I think that tooling does not really deal with the notion of MappedSuperclass? +It's uncertain whether the net effect on consuming this model (to build the persister model) is positive or negative. +It's also yet another big change. + +=== SecondaryTable + +"Nice" to have... + +`org.hibernate.mapping.Join` models what JPA calls a SecondaryTable, but in a way that is a little awkward for building these from xml or annotations. +Specifically, `Join` tracks the attributes mapped to it separate from the `PersistentClass` attributes. +The attributes kept on `PersistentClass` are the ones mapped to the "root" table +The complete set of attributes for an entity are the `PersistentClass` ones plus the ones for each of its `Join`s. + +There is a lot of benefit to modeling this how we do (even with the awkwardness), so maybe we just leave this one. +