Merge remote-tracking branch 'upstream/master' into wip/6.0
This commit is contained in:
commit
4e22c5cabc
|
@ -0,0 +1,4 @@
|
|||
.asciidoctor
|
||||
*.png
|
||||
*.html
|
||||
*.pdf
|
|
@ -0,0 +1,424 @@
|
|||
:link-parallelArrays: https://en.wikipedia.org/wiki/Parallel_array["parallel arrays"]
|
||||
= Domain Model Mappings
|
||||
|
||||
:toc2:
|
||||
:toclevels: 3
|
||||
:sectanchors:
|
||||
:numbered:
|
||||
|
||||
Describes Hibernate's handling of domain model metadata
|
||||
|
||||
== Mapping sources
|
||||
|
||||
Mapping sources include `hbm.xml` files, `orm.xml` files and annotated classes. There are
|
||||
other specialized forms of sources, but they all come back to locating annotated classes
|
||||
and XML mappings.
|
||||
|
||||
The main actors in managing the sources include:
|
||||
|
||||
`MetadataSources`::
|
||||
Used to collect mapping sources to be processed together
|
||||
|
||||
`JaxbHbmHibernateMapping`::
|
||||
Main JAXB binding for a `hbm.xml` mapping document
|
||||
|
||||
`Binding`::
|
||||
Represents an XML mapping within the `MetadataSources`. Wraps either a
|
||||
`JaxbHbmHibernateMapping` or DOM `Document` representing a JPA `orm.xml`.
|
||||
|
||||
`MappingBinder`::
|
||||
Responsible for generating `Binding` instances.
|
||||
|
||||
The handling for XML mappings is as follows:
|
||||
|
||||
[plantuml,hbm,png]
|
||||
.hbm.xml processing
|
||||
----
|
||||
@startuml
|
||||
skinparam handwritten true
|
||||
|
||||
Application -> MetadataSources : add(hbm.xml)
|
||||
MetadataSources -> MappingBinder : parse(hbm.xml)
|
||||
MappingBinder -> JAXB : bind(hbm.xml)
|
||||
MappingBinder <- JAXB : JaxbHbmHibernateMapping
|
||||
MetadataSources <- MappingBinder : Binding<JaxbHbmHibernateMapping>
|
||||
|
||||
@enduml
|
||||
----
|
||||
|
||||
[plantuml,orm,png]
|
||||
.orm.xml processing
|
||||
----
|
||||
@startuml
|
||||
skinparam handwritten true
|
||||
|
||||
Application -> MetadataSources : add(orm.xml)
|
||||
MetadataSources -> MappingBinder : parse(orm.xml)
|
||||
MappingBinder -> DOM : bind(orm.xml)
|
||||
MappingBinder <- DOM : Document
|
||||
MetadataSources <- MappingBinder : Binding<Document>
|
||||
|
||||
@enduml
|
||||
----
|
||||
|
||||
NOTE: `MetadataSources` receives XML files without any knowledge of whether the file
|
||||
is a Hibernate mapping (`hbm.xml`) or a JPA mapping (`orm.xml`). `MappingBinder` makes
|
||||
that distinction based on doctype, schema, etc.
|
||||
|
||||
|
||||
== Boot-time metamodel
|
||||
|
||||
The `org.hibernate.mapping` package defines most of the boot-time model.
|
||||
|
||||
|
||||
[plantuml,bootmodel,png]
|
||||
.Boot model actors
|
||||
----
|
||||
@startmindmap
|
||||
skinparam handwritten true
|
||||
+ Boot model
|
||||
++ PersistentClass
|
||||
++ Property
|
||||
++ Value
|
||||
++ IdGenerator
|
||||
++ TypeDef
|
||||
-- Table
|
||||
-- Selectable
|
||||
-- PrimaryKey
|
||||
-- Constraint
|
||||
@endmindmap
|
||||
----
|
||||
|
||||
=== PersistentClass
|
||||
|
||||
Models an entity
|
||||
|
||||
[plantuml,persistentclass,png]
|
||||
.PersistentClass hierarchy
|
||||
----
|
||||
@startuml
|
||||
interface Value
|
||||
|
||||
class Property
|
||||
Property -- Value : value >
|
||||
|
||||
class PersistentClass {
|
||||
entityName : String
|
||||
}
|
||||
PersistentClass *- Property : properties >
|
||||
|
||||
class RootClass {
|
||||
table : Table
|
||||
}
|
||||
|
||||
class JoinedSubclass {
|
||||
table : Table
|
||||
}
|
||||
|
||||
class UnionSubclass {
|
||||
table : Table
|
||||
}
|
||||
|
||||
PersistentClass <|-- RootClass
|
||||
PersistentClass <|-- Subclass
|
||||
Subclass <|-- JoinedSubclass
|
||||
Subclass <|-- SingleTableSubclass
|
||||
Subclass <|-- UnionSubclass
|
||||
@enduml
|
||||
----
|
||||
|
||||
|
||||
=== Value
|
||||
|
||||
Models a value. A value ultimately corresponds to a `org.hibernate.type.Type`. We will discuss
|
||||
this "simple" distinction when we talk about Types in the run-time metamodel section.
|
||||
|
||||
|
||||
[plantuml,value,png]
|
||||
.Value hierarchy
|
||||
----
|
||||
@startuml
|
||||
class SimpleValue
|
||||
note left of SimpleValue : By itself represents\na basic value
|
||||
class OneToMany
|
||||
note top of OneToMany : Used as element descriptor for\none-to-many collections
|
||||
|
||||
Value <|-- KeyValue
|
||||
Value <|-- OneToMany
|
||||
|
||||
KeyValue <|-- SimpleValue
|
||||
|
||||
SimpleValue <|-- DependentValue
|
||||
|
||||
SimpleValue <|-- Component
|
||||
|
||||
SimpleValue <|-- Any
|
||||
|
||||
SimpleValue <|-- ToOne
|
||||
ToOne <|-- ManyToOne
|
||||
ToOne <|-- OneToOne
|
||||
|
||||
Value <|-- Collection
|
||||
Collection <|-- Bag
|
||||
Collection <|-- Set
|
||||
Collection <|-- IdentifierCollection
|
||||
IdentifierCollection <|-- IdentifierBag
|
||||
Collection <|-- IndexedCollection
|
||||
IndexedCollection <|-- List
|
||||
List <|-- Array
|
||||
IndexedCollection <|-- Map
|
||||
|
||||
@enduml
|
||||
----
|
||||
|
||||
|
||||
=== Database model
|
||||
|
||||
[plantuml,db,png]
|
||||
.Database model
|
||||
----
|
||||
@startuml
|
||||
class Identifier
|
||||
Identifier : String text
|
||||
Identifier : boolean quoted
|
||||
|
||||
Selectable <|-- Column
|
||||
Column : Identifider name
|
||||
|
||||
Selectable <|-- Formula
|
||||
Formula : String fragment
|
||||
|
||||
Constraint <|-- PrimaryKey
|
||||
Constraint <|-- UniqueKey
|
||||
Constraint <|-- ForeignKey
|
||||
|
||||
class Table
|
||||
Table : Identifier name
|
||||
Table : Identifier schema
|
||||
Table : Identifier catalog
|
||||
Table : PrimaryKey : primaryKey
|
||||
Table : Selectable : selectables
|
||||
|
||||
class Index
|
||||
class Sequence
|
||||
|
||||
interface Exportable
|
||||
Exportable <|-- Table
|
||||
Exportable <|-- Constraint
|
||||
Exportable <|-- Index
|
||||
Exportable <|-- Sequence
|
||||
Exportable <|-- AuxilaryDatabaseObject
|
||||
|
||||
interface TableOwner
|
||||
TableOwner : Table table
|
||||
|
||||
TableOwner <|-- RootClass
|
||||
TableOwner <|-- JoinedSubclass
|
||||
TableOwner <|-- UnionSubclass
|
||||
@enduml
|
||||
----
|
||||
|
||||
|
||||
=== Transition from sources to boot-time model
|
||||
|
||||
The boot-time metamodel is built iteratively. The general paradigm in this transition is to
|
||||
instantiate one of these boot-time objects which are then populated in multiple later steps (via
|
||||
setters, additions, etc).
|
||||
|
||||
The main actors in this process are `HbmMetadataSourceProcessorImpl` and `AnnotationMetadataSourceProcessorImpl`.
|
||||
|
||||
|
||||
[plantuml,source2boot,png]
|
||||
.Transition sources to boot-time model
|
||||
----
|
||||
@startuml
|
||||
skinparam handwritten true
|
||||
autonumber
|
||||
|
||||
Application -> MetadataBuilder : build()
|
||||
MetadataBuilder -> MetadataBuildingProcess : build()
|
||||
MetadataBuildingProcess -> MetadataSourceProcessor
|
||||
|
||||
MetadataSourceProcessor -> HbmMetadataSourceProcessorImpl : process hbm.xml Bindings
|
||||
|
||||
MetadataSourceProcessor -> AnnotationMetadataSourceProcessorImpl : process annotations + orm.xml Bindings
|
||||
|
||||
MetadataBuilder <- MetadataBuildingProcess : Metadata
|
||||
Application <- MetadataBuilder : Metadata
|
||||
|
||||
@enduml
|
||||
----
|
||||
|
||||
|
||||
== Run-time metamodel
|
||||
|
||||
|
||||
[plantuml,runtimemodel,png]
|
||||
.Run-time model actors
|
||||
----
|
||||
@startmindmap
|
||||
skinparam handwritten true
|
||||
+ Boot model
|
||||
++ EntityPersister
|
||||
++ CollectionPersister
|
||||
++ Tuplizer
|
||||
-- Type
|
||||
-- IdentifierGenerator
|
||||
@endmindmap
|
||||
----
|
||||
|
||||
=== EntityPersister
|
||||
|
||||
Manages persistence of an entity to/from its defined table(s). Maintains flattened
|
||||
state regarding various aspects of the entity's value mappings as {link-parallelArrays}.
|
||||
An entity's value mappings include:
|
||||
* identifier
|
||||
* attribute state
|
||||
* (discriminator)
|
||||
* (version)
|
||||
|
||||
[plantuml,entitypersister,png]
|
||||
.EntityPersister hierarchy
|
||||
----
|
||||
@startuml
|
||||
skinparam handwritten true
|
||||
interface EntityPersister
|
||||
|
||||
abstract class AbstractEntityPersister
|
||||
EntityPersister <|-- AbstractEntityPersister
|
||||
|
||||
AbstractEntityPersister <|-- SingleTableEntityPersister
|
||||
AbstractEntityPersister <|-- JoinedEntityPersister
|
||||
AbstractEntityPersister <|-- UnionEntityPersister
|
||||
@enduml
|
||||
----
|
||||
|
||||
|
||||
=== CollectionPersister
|
||||
|
||||
Manages persistence of a collection to its defined table(s). Maintains flattened
|
||||
state as {link-parallelArrays} regarding various aspects of the value mappings making
|
||||
up the collection. These aspects include:
|
||||
* key -- the FK
|
||||
* element
|
||||
* (identifier) -- @IdBag
|
||||
* (list-index | map-key)
|
||||
|
||||
[plantuml,collectionpersister,png]
|
||||
.CollectionPersister hierarchy
|
||||
----
|
||||
@startuml
|
||||
skinparam handwritten true
|
||||
interface CollectionPersister
|
||||
|
||||
abstract class AbstractCollectionPersister
|
||||
CollectionPersister <|-- CollectionPersister
|
||||
|
||||
AbstractCollectionPersister <|-- BasicCollectionPersister
|
||||
AbstractCollectionPersister <|-- OneToManyCollectionPersister
|
||||
|
||||
note left of BasicCollectionPersister : collection mappings\nwith a collection table
|
||||
@enduml
|
||||
----
|
||||
|
||||
=== Type
|
||||
|
||||
Describes a value mapping which is some form of non-identified state.
|
||||
|
||||
[plantuml,type,png]
|
||||
.Type hierarchy
|
||||
----
|
||||
@startuml
|
||||
skinparam handwritten true
|
||||
|
||||
interface Type
|
||||
|
||||
interface IdentifierType
|
||||
Type <|-- IdentifierType
|
||||
|
||||
interface DiscriminatorType
|
||||
IdentifierType <|-- DiscriminatorType
|
||||
|
||||
interface VersionType
|
||||
Type <|-- VersionType
|
||||
|
||||
interface BasicType
|
||||
Type <|-- BasicType
|
||||
|
||||
interface CompositeType
|
||||
Type <|-- CompositeType
|
||||
CompositeType *- Type : subtypes
|
||||
|
||||
interface AssociationType
|
||||
Type <|-- AssociationType
|
||||
|
||||
interface AnyType {
|
||||
discriminatorType : DiscriminatorType
|
||||
identifierType : IdentifierType
|
||||
}
|
||||
AssociationType <|-- AnyType
|
||||
CompositeType <|-- AnyType
|
||||
|
||||
interface UserType
|
||||
interface CustomType
|
||||
CustomType -- UserType : wrappedUserType
|
||||
Type <|-- CustomType
|
||||
@enduml
|
||||
----
|
||||
|
||||
`IdentifierType`::
|
||||
Specialized Type contract for types that can be used as an identifier
|
||||
|
||||
`DiscriminatorType`::
|
||||
Specialized Type contract for types that can be used as a discriminator
|
||||
|
||||
`VersionType`::
|
||||
Specialized Type contract for types that can be used as a version
|
||||
|
||||
`BasicType`::
|
||||
Mapping to a single column
|
||||
|
||||
`CompositeType`::
|
||||
Mapping to one or more columns
|
||||
|
||||
`AssociationType`::
|
||||
Mapping to an entity association
|
||||
|
||||
`AnyType`::
|
||||
Models a discriminated association which is similar to an association referencing a
|
||||
discriminated-subclass entity in that the mapping involves a discriminator. However,
|
||||
in an ANY mapping the discriminator is on the referring side. This will map to at least
|
||||
2 columns - one for the discriminator plus one or more identifier columns.
|
||||
|
||||
`EntityType`::
|
||||
Models a foreign-key, which "from this side" is a to-one. Could map to a single column or multiple.
|
||||
|
||||
`CollectionType`::
|
||||
Models a foreign-key, which "from this side" is a to-many. Will map to at
|
||||
|
||||
|
||||
=== Transition from boot-time model to run-time model
|
||||
|
||||
This transition involves processing the boot model objects (`PersistentClass`, `Value`, etc) and building
|
||||
the corresponding run-time counterparts (`EntityPersister`, `Type`, etc).
|
||||
|
||||
The main actors in this transition are the `SessionFactory` itself, `MetamodelImplementor` and
|
||||
`TypeConfiguration`:
|
||||
|
||||
|
||||
[plantuml,boot2run,png]
|
||||
.Transition boot-time model to run-time model
|
||||
----
|
||||
@startuml
|
||||
skinparam handwritten true
|
||||
|
||||
Application -> SessionFactoryBuilder : build()
|
||||
SessionFactoryBuilder -> SessionFactory : new
|
||||
SessionFactory -> TypeConfiguration : scope
|
||||
|
||||
...
|
||||
|
||||
@enduml
|
||||
----
|
||||
|
||||
##
|
|
@ -684,7 +684,7 @@ Sets the associated collection cache concurrency strategy for the designated reg
|
|||
=== Infinispan properties
|
||||
|
||||
For more details about how to customize the Infinispan second-level cache provider, check out the
|
||||
http://infinispan.org/docs/stable/user_guide/user_guide.html#configuration_properties[Infinispan User Guide].
|
||||
http://infinispan.org/docs/stable/titles/integrating/integrating.html#configuration_properties[Infinispan User Guide].
|
||||
|
||||
[[configurations-transactions]]
|
||||
=== Transactions properties
|
||||
|
|
|
@ -707,4 +707,4 @@ Infinispan is a distributed in-memory key/value data store, available as a cache
|
|||
It supports advanced functionality such as transactions, events, querying, distributed processing, off-heap and geographical failover.
|
||||
|
||||
For more details, check out the
|
||||
http://infinispan.org/docs/stable/user_guide/user_guide.html#integrations_jpa_hibernate[Infinispan User Guide].
|
||||
http://infinispan.org/docs/stable/titles/integrating/integrating.html#integrating_jpa_hibernate[Infinispan User Guide].
|
|
@ -8,7 +8,7 @@ package org.hibernate.boot.archive.internal;
|
|||
|
||||
import java.net.URL;
|
||||
|
||||
import org.hibernate.annotations.common.AssertionFailure;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.boot.archive.spi.ArchiveContext;
|
||||
import org.hibernate.boot.archive.spi.ArchiveDescriptor;
|
||||
import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory;
|
||||
|
|
|
@ -86,6 +86,8 @@ import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
|||
import org.hibernate.id.factory.spi.MutableIdentifierGeneratorFactory;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.SessionFactoryImpl;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Column;
|
||||
|
|
|
@ -1083,7 +1083,7 @@ public class BinderHelper {
|
|||
if ( declaringClass != null ) {
|
||||
final InheritanceState inheritanceState = inheritanceStatePerClass.get( declaringClass );
|
||||
if ( inheritanceState == null ) {
|
||||
throw new org.hibernate.annotations.common.AssertionFailure(
|
||||
throw new AssertionFailure(
|
||||
"Declaring class is not found in the inheritance state hierarchy: " + declaringClass
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import javax.persistence.Convert;
|
|||
import javax.persistence.Converts;
|
||||
import javax.persistence.JoinTable;
|
||||
|
||||
import org.hibernate.annotations.common.AssertionFailure;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
|
|
|
@ -31,6 +31,7 @@ import javax.persistence.MapKeyColumn;
|
|||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.FetchMode;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.BatchSize;
|
||||
|
@ -64,7 +65,6 @@ import org.hibernate.annotations.SortNatural;
|
|||
import org.hibernate.annotations.SortType;
|
||||
import org.hibernate.annotations.Where;
|
||||
import org.hibernate.annotations.WhereJoinTable;
|
||||
import org.hibernate.annotations.common.AssertionFailure;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.boot.model.IdentifierGeneratorDefinition;
|
||||
|
|
|
@ -13,6 +13,7 @@ import javax.persistence.Id;
|
|||
import javax.persistence.Lob;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.annotations.AttributeAccessor;
|
||||
import org.hibernate.annotations.Generated;
|
||||
|
@ -20,7 +21,6 @@ import org.hibernate.annotations.Immutable;
|
|||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.annotations.OptimisticLock;
|
||||
import org.hibernate.annotations.ValueGenerationType;
|
||||
import org.hibernate.annotations.common.AssertionFailure;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
|
|
|
@ -12,8 +12,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import javax.validation.Path;
|
||||
import javax.validation.TraversableResolver;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.annotations.common.AssertionFailure;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.type.CollectionType;
|
||||
|
|
|
@ -10,7 +10,6 @@ import java.lang.reflect.InvocationTargetException;
|
|||
import java.util.Map;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.annotations.common.util.StringHelper;
|
||||
import org.hibernate.boot.registry.selector.spi.StrategySelectionException;
|
||||
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
@ -21,6 +20,7 @@ import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfoSource;
|
|||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolver;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.service.spi.ServiceRegistryAwareService;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
|
||||
|
|
|
@ -17,11 +17,10 @@ import javax.naming.event.NamingExceptionEvent;
|
|||
import javax.naming.spi.ObjectFactory;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.annotations.common.util.StringHelper;
|
||||
import org.hibernate.engine.jndi.JndiException;
|
||||
import org.hibernate.engine.jndi.JndiNameException;
|
||||
import org.hibernate.engine.jndi.spi.JndiService;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
/**
|
||||
* A registry of all {@link SessionFactory} instances for the same classloader as this class.
|
||||
|
|
|
@ -17,10 +17,10 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.annotations.common.util.StringHelper;
|
||||
import org.hibernate.boot.model.relational.Exportable;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.Mapping;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
/**
|
||||
* A relational constraint.
|
||||
|
|
|
@ -16,8 +16,8 @@ import javax.persistence.OneToOne;
|
|||
import javax.persistence.metamodel.Attribute;
|
||||
import javax.persistence.metamodel.Type;
|
||||
|
||||
import org.hibernate.annotations.common.AssertionFailure;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.internal.EntityManagerMessageLogger;
|
||||
import org.hibernate.internal.HEMLogging;
|
||||
import org.hibernate.mapping.Collection;
|
||||
|
|
|
@ -23,7 +23,8 @@ import javax.persistence.metamodel.Type;
|
|||
import org.hibernate.Internal;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.annotations.common.AssertionFailure;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.EntityManagerMessageLogger;
|
||||
import org.hibernate.internal.HEMLogging;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.criteria.size;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH014245")
|
||||
public class CriteriaSelectSizeCollectionTest extends BaseEntityManagerFunctionalTestCase {
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Customer.class, Alias.class };
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Customer customer = new Customer( "1", "Phil" );
|
||||
Alias alias = new Alias( "2", "p" );
|
||||
customer.addAlias( alias );
|
||||
entityManager.persist( customer );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectCollectionSize() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Integer> query = criteriaBuilder.createQuery( Integer.class );
|
||||
Root<Customer> customer = query.from( Customer.class );
|
||||
|
||||
Expression<Integer> aliases = criteriaBuilder.size( customer.get( "aliases" ) );
|
||||
query.select( aliases );
|
||||
query.where( criteriaBuilder.equal( customer.get( "id" ), "1" ) );
|
||||
|
||||
TypedQuery<Integer> tq = entityManager.createQuery( query );
|
||||
Integer size = tq.getSingleResult();
|
||||
assertThat( size, is( 1 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "Customer")
|
||||
@Table(name = "CUSTOMER_TABLE")
|
||||
public static class Customer {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
@ManyToMany(cascade = CascadeType.ALL)
|
||||
private Collection<Alias> aliases = new ArrayList<>();
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(String id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void addAlias(Alias alias) {
|
||||
aliases.add( alias );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Alias")
|
||||
@Table(name = "ALIAS_TABLE")
|
||||
public static class Alias implements java.io.Serializable {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
private String alias;
|
||||
|
||||
public Alias() {
|
||||
}
|
||||
|
||||
public Alias(String id, String alias) {
|
||||
this.id = id;
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public void setAlias(String alias) {
|
||||
this.alias = alias;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue