HHH-4529 support for derived entity id as a XToOne pointing to the master entity

HHH-4840 support for Core style embedded id (after all these years :) )

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18619 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Emmanuel Bernard 2010-01-25 17:19:05 +00:00
parent 671d9db8e2
commit d00f7efb30
12 changed files with 439 additions and 102 deletions

View File

@ -625,10 +625,10 @@ else if ( InheritanceType.TABLE_PER_CLASS.equals( inheritanceState.getType() ) )
HashMap<String, IdGenerator> classGenerators = buildLocalGenerators( clazzToProcess, mappings ); HashMap<String, IdGenerator> classGenerators = buildLocalGenerators( clazzToProcess, mappings );
// check properties // check properties
List<PropertyData> elements = final ElementsToProcess elementsToProcess = getElementsToProcess(
getElementsToProcess( persistentClass, clazzToProcess, inheritanceStatePerClass, entityBinder, mappings
persistentClass, clazzToProcess, inheritanceStatePerClass, entityBinder, mappings );
);
final boolean subclassAndSingleTableStrategy = inheritanceState.getType() == InheritanceType.SINGLE_TABLE final boolean subclassAndSingleTableStrategy = inheritanceState.getType() == InheritanceType.SINGLE_TABLE
&& inheritanceState.hasParents(); && inheritanceState.hasParents();
//process idclass if any //process idclass if any
@ -674,7 +674,9 @@ else if ( InheritanceType.TABLE_PER_CLASS.equals( inheritanceState.getType() ) )
isComponent, isComponent,
propertyAccessor, entityBinder, propertyAccessor, entityBinder,
true, true,
false, mappings, inheritanceStatePerClass false,
mappings,
inheritanceStatePerClass
); );
inferredData = new PropertyPreloadedData( inferredData = new PropertyPreloadedData(
propertyAccessor, "_identifierMapper", compositeClass propertyAccessor, "_identifierMapper", compositeClass
@ -683,9 +685,11 @@ else if ( InheritanceType.TABLE_PER_CLASS.equals( inheritanceState.getType() ) )
propertyHolder, propertyHolder,
inferredData, inferredData,
baseInferredData, baseInferredData,
propertyAccessor, false, propertyAccessor,
false,
entityBinder, entityBinder,
true, true, true,
true,
false, mappings, inheritanceStatePerClass false, mappings, inheritanceStatePerClass
); );
entityBinder.setIgnoreIdAnnotations( ignoreIdAnnotations ); entityBinder.setIgnoreIdAnnotations( ignoreIdAnnotations );
@ -720,8 +724,11 @@ else if ( InheritanceType.TABLE_PER_CLASS.equals( inheritanceState.getType() ) )
idProperties.add( ( (Property) properties.next() ).getName() ); idProperties.add( ( (Property) properties.next() ).getName() );
} }
} }
else {
entityBinder.setWrapIdsInEmbeddedComponents( elementsToProcess.getIdPropertyCount() > 1 );
}
Set<String> missingIdProperties = new HashSet<String>( idProperties ); Set<String> missingIdProperties = new HashSet<String>( idProperties );
for (PropertyData propertyAnnotatedElement : elements) { for (PropertyData propertyAnnotatedElement : elementsToProcess.getElements() ) {
String propertyName = propertyAnnotatedElement.getPropertyName(); String propertyName = propertyAnnotatedElement.getPropertyName();
if ( !idProperties.contains( propertyName ) ) { if ( !idProperties.contains( propertyName ) ) {
processElementAnnotations( processElementAnnotations(
@ -979,7 +986,7 @@ private static boolean isEntityClassType(XClass clazzToProcess, AnnotatedClassTy
* Get the annotated elements, guessing the access type from @Id or @EmbeddedId presence. * Get the annotated elements, guessing the access type from @Id or @EmbeddedId presence.
* Change EntityBinder by side effect * Change EntityBinder by side effect
*/ */
private static List<PropertyData> getElementsToProcess( private static ElementsToProcess getElementsToProcess(
PersistentClass persistentClass, XClass clazzToProcess, PersistentClass persistentClass, XClass clazzToProcess,
Map<XClass, InheritanceState> inheritanceStatePerClass, Map<XClass, InheritanceState> inheritanceStatePerClass,
EntityBinder entityBinder, ExtendedMappings mappings EntityBinder entityBinder, ExtendedMappings mappings
@ -996,21 +1003,39 @@ private static List<PropertyData> getElementsToProcess(
List<PropertyData> elements = new ArrayList<PropertyData>(); List<PropertyData> elements = new ArrayList<PropertyData>();
int deep = classesToProcess.size(); int deep = classesToProcess.size();
boolean hasIdentifier = false; int idPropertyCount = 0;
for ( int index = 0; index < deep; index++ ) { for ( int index = 0; index < deep; index++ ) {
PropertyContainer properyContainer = new PropertyContainer( classesToProcess.get( index ), clazzToProcess ); PropertyContainer propertyContainer = new PropertyContainer( classesToProcess.get( index ), clazzToProcess );
boolean currentHasIdentifier = addElementsOfClass( elements, accessType, properyContainer, mappings ); int currentIdPropertyCount = addElementsOfClass( elements, accessType, propertyContainer, mappings );
hasIdentifier = hasIdentifier || currentHasIdentifier; idPropertyCount += currentIdPropertyCount;
} }
entityBinder.setPropertyAccessType( accessType ); entityBinder.setPropertyAccessType( accessType );
if ( !hasIdentifier && !inheritanceState.hasParents() ) { if ( idPropertyCount == 0 && !inheritanceState.hasParents() ) {
throw new AnnotationException( "No identifier specified for entity: " + clazzToProcess.getName() ); throw new AnnotationException( "No identifier specified for entity: " + clazzToProcess.getName() );
} }
return elements; return new ElementsToProcess( elements, idPropertyCount);
}
private static final class ElementsToProcess {
private final List<PropertyData> properties;
private final int idPropertyCount;
public List<PropertyData> getElements() {
return properties;
}
public int getIdPropertyCount() {
return idPropertyCount;
}
private ElementsToProcess(List<PropertyData> properties, int idPropertyCount) {
this.properties = properties;
this.idPropertyCount = idPropertyCount;
}
} }
private static AccessType determineDefaultAccessType(XClass annotatedClass, Map<XClass, InheritanceState> inheritanceStatePerClass) { private static AccessType determineDefaultAccessType(XClass annotatedClass, Map<XClass, InheritanceState> inheritanceStatePerClass) {
@ -1207,13 +1232,13 @@ private static void bindDiscriminatorToPersistentClass(
* strategy is used * strategy is used
* @param propertyContainer Metadata about a class and its properties * @param propertyContainer Metadata about a class and its properties
* @param mappings Mapping meta data * @param mappings Mapping meta data
* @return {@code true} in case an id property was found while iterating the elements of {@code annoatedClass} using * @return the number of id properties found while iterating the elements of {@code annoatedClass} using
* the determined access strategy, {@code false} otherwise. * the determined access strategy, {@code false} otherwise.
*/ */
private static boolean addElementsOfClass( private static int addElementsOfClass(
List<PropertyData> elements, AccessType defaultAccessType, PropertyContainer propertyContainer, ExtendedMappings mappings List<PropertyData> elements, AccessType defaultAccessType, PropertyContainer propertyContainer, ExtendedMappings mappings
) { ) {
boolean hasIdentifier = false; int idPropertyCounter = 0;
AccessType accessType = defaultAccessType; AccessType accessType = defaultAccessType;
if ( propertyContainer.hasExplicitAccessStrategy() ) { if ( propertyContainer.hasExplicitAccessStrategy() ) {
@ -1223,21 +1248,21 @@ private static boolean addElementsOfClass(
propertyContainer.assertTypesAreResolvable( accessType ); propertyContainer.assertTypesAreResolvable( accessType );
Collection<XProperty> properties = propertyContainer.getProperties( accessType ); Collection<XProperty> properties = propertyContainer.getProperties( accessType );
for ( XProperty p : properties ) { for ( XProperty p : properties ) {
final boolean currentHasIdentifier = addProperty( final int currentIdPropertyCounter = addProperty(
propertyContainer, p, elements, accessType.getType(), mappings propertyContainer, p, elements, accessType.getType(), mappings
); );
hasIdentifier = hasIdentifier || currentHasIdentifier; idPropertyCounter += currentIdPropertyCounter;
} }
return hasIdentifier; return idPropertyCounter;
} }
private static boolean addProperty( private static int addProperty(
PropertyContainer propertyContainer, XProperty property, List<PropertyData> annElts, PropertyContainer propertyContainer, XProperty property, List<PropertyData> annElts,
String propertyAccessor, ExtendedMappings mappings String propertyAccessor, ExtendedMappings mappings
) { ) {
final XClass declaringClass = propertyContainer.getDeclaringClass(); final XClass declaringClass = propertyContainer.getDeclaringClass();
final XClass entity = propertyContainer.getEntityAtStake(); final XClass entity = propertyContainer.getEntityAtStake();
boolean hasIdentifier; int idPropertyCounter = 0;
PropertyData propertyAnnotatedElement = new PropertyInferredData( PropertyData propertyAnnotatedElement = new PropertyInferredData(
declaringClass, property, propertyAccessor, declaringClass, property, propertyAccessor,
mappings.getReflectionManager() ); mappings.getReflectionManager() );
@ -1249,17 +1274,16 @@ private static boolean addProperty(
final XAnnotatedElement element = propertyAnnotatedElement.getProperty(); final XAnnotatedElement element = propertyAnnotatedElement.getProperty();
if ( element.isAnnotationPresent( Id.class ) || element.isAnnotationPresent( EmbeddedId.class ) ) { if ( element.isAnnotationPresent( Id.class ) || element.isAnnotationPresent( EmbeddedId.class ) ) {
annElts.add( 0, propertyAnnotatedElement ); annElts.add( 0, propertyAnnotatedElement );
hasIdentifier = true; idPropertyCounter++;
} }
else { else {
annElts.add( propertyAnnotatedElement ); annElts.add( propertyAnnotatedElement );
hasIdentifier = false;
} }
if ( element.isAnnotationPresent( MapsId.class ) ) { if ( element.isAnnotationPresent( MapsId.class ) ) {
mappings.addPropertyAnnotatedWithMapsId( entity, propertyAnnotatedElement ); mappings.addPropertyAnnotatedWithMapsId( entity, propertyAnnotatedElement );
} }
return hasIdentifier; return idPropertyCounter;
} }
/* /*
@ -1361,9 +1385,28 @@ else if ( joinColumns == null && property.isAnnotationPresent( org.hibernate.ann
final XClass returnedClass = inferredData.getClassOrElement(); final XClass returnedClass = inferredData.getClassOrElement();
//prepare PropertyBinder
PropertyBinder propertyBinder = new PropertyBinder();
propertyBinder.setName( inferredData.getPropertyName() );
propertyBinder.setReturnedClassName( inferredData.getTypeName() );
propertyBinder.setAccessType( inferredData.getDefaultAccess() );
propertyBinder.setHolder( propertyHolder );
propertyBinder.setProperty( property );
propertyBinder.setReturnedClass( inferredData.getPropertyClass() );
propertyBinder.setMappings( mappings );
if ( isIdentifierMapper ) {
propertyBinder.setInsertable( false );
propertyBinder.setUpdatable( false );
}
propertyBinder.setDeclaringClass( inferredData.getDeclaringClass() );
propertyBinder.setEntityBinder( entityBinder );
propertyBinder.setInheritanceStatePerClass(inheritanceStatePerClass);
boolean isId = !entityBinder.isIgnoreIdAnnotations() && boolean isId = !entityBinder.isIgnoreIdAnnotations() &&
( property.isAnnotationPresent( Id.class ) ( property.isAnnotationPresent( Id.class )
|| property.isAnnotationPresent( EmbeddedId.class ) ); || property.isAnnotationPresent( EmbeddedId.class ) );
propertyBinder.setId( isId );
if ( property.isAnnotationPresent( Version.class ) ) { if ( property.isAnnotationPresent( Version.class ) ) {
if ( isIdentifierMapper ) { if ( isIdentifierMapper ) {
throw new AnnotationException( throw new AnnotationException(
@ -1384,19 +1427,14 @@ else if ( joinColumns == null && property.isAnnotationPresent( org.hibernate.ann
} }
log.trace( "{} is a version property", inferredData.getPropertyName() ); log.trace( "{} is a version property", inferredData.getPropertyName() );
RootClass rootClass = (RootClass) propertyHolder.getPersistentClass(); RootClass rootClass = (RootClass) propertyHolder.getPersistentClass();
PropertyBinder propBinder = new PropertyBinder(); // PropertyBinder propBinder = new PropertyBinder();
propBinder.setName( inferredData.getPropertyName() ); // propBinder.setName( inferredData.getPropertyName() );
propBinder.setReturnedClassName( inferredData.getTypeName() ); // propBinder.setReturnedClassName( inferredData.getTypeName() );
propBinder.setLazy( false ); // propBinder.setLazy( false );
propBinder.setAccessType( inferredData.getDefaultAccess() ); // propBinder.setAccessType( inferredData.getDefaultAccess() );
propBinder.setColumns( columns ); propertyBinder.setColumns( columns );
propBinder.setHolder( propertyHolder ); //PropertyHolderBuilder.buildPropertyHolder(rootClass) Property prop = propertyBinder.makePropertyValueAndBind();
propBinder.setProperty( property ); propertyBinder.getSimpleValueBinder().setVersion(true);
propBinder.setReturnedClass( inferredData.getPropertyClass() );
propBinder.setMappings( mappings );
propBinder.setDeclaringClass( inferredData.getDeclaringClass() );
Property prop = propBinder.makePropertyValueAndBind();
propBinder.getSimpleValueBinder().setVersion(true);
rootClass.setVersion( prop ); rootClass.setVersion( prop );
//If version is on a mapped superclass, update the mapping //If version is on a mapped superclass, update the mapping
@ -1451,7 +1489,8 @@ else if ( property.isAnnotationPresent( ManyToOne.class ) ) {
ignoreNotFound, onDeleteCascade, ignoreNotFound, onDeleteCascade,
ToOneBinder.getTargetEntity( inferredData, mappings ), ToOneBinder.getTargetEntity( inferredData, mappings ),
propertyHolder, propertyHolder,
inferredData, false, isIdentifierMapper, inSecondPass, mappings inferredData, false, isIdentifierMapper,
inSecondPass, propertyBinder, mappings
); );
} }
else if ( property.isAnnotationPresent( OneToOne.class ) ) { else if ( property.isAnnotationPresent( OneToOne.class ) ) {
@ -1489,7 +1528,13 @@ else if ( property.isAnnotationPresent( OneToOne.class ) ) {
ignoreNotFound, onDeleteCascade, ignoreNotFound, onDeleteCascade,
ToOneBinder.getTargetEntity( inferredData, mappings ), ToOneBinder.getTargetEntity( inferredData, mappings ),
propertyHolder, propertyHolder,
inferredData, ann.mappedBy(), trueOneToOne, isIdentifierMapper, inSecondPass, mappings inferredData,
ann.mappedBy(),
trueOneToOne,
isIdentifierMapper,
inSecondPass,
propertyBinder,
mappings
); );
} }
else if ( property.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) { else if ( property.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) {
@ -1793,7 +1838,7 @@ else if ( !isId || !entityBinder.isIgnoreIdAnnotations() ) {
isComponent = property.isAnnotationPresent( Embedded.class ) isComponent = property.isAnnotationPresent( Embedded.class )
|| property.isAnnotationPresent( EmbeddedId.class ) || property.isAnnotationPresent( EmbeddedId.class )
|| returnedClass.isAnnotationPresent( Embeddable.class ); || returnedClass.isAnnotationPresent( Embeddable.class );
PropertyBinder propertyBinder;
if ( isComponent ) { if ( isComponent ) {
AccessType propertyAccessor = entityBinder.getPropertyAccessor( property ); AccessType propertyAccessor = entityBinder.getPropertyAccessor( property );
propertyBinder = bindComponent( propertyBinder = bindComponent(
@ -1835,23 +1880,12 @@ else if ( !isId || !entityBinder.isIgnoreIdAnnotations() ) {
mappings ); mappings );
} }
propertyBinder = new PropertyBinder();
propertyBinder.setName( inferredData.getPropertyName() );
propertyBinder.setReturnedClassName( inferredData.getTypeName() );
propertyBinder.setLazy( lazy ); propertyBinder.setLazy( lazy );
propertyBinder.setAccessType( inferredData.getDefaultAccess() );
propertyBinder.setColumns( columns ); propertyBinder.setColumns( columns );
propertyBinder.setHolder( propertyHolder ); // if ( isIdentifierMapper ) {
propertyBinder.setProperty( property ); // propertyBinder.setInsertable( false );
propertyBinder.setReturnedClass( inferredData.getPropertyClass() ); // propertyBinder.setUpdatable( false );
propertyBinder.setMappings( mappings ); // }
if ( isIdentifierMapper ) {
propertyBinder.setInsertable( false );
propertyBinder.setUpdatable( false );
}
propertyBinder.setDeclaringClass( inferredData.getDeclaringClass() );
propertyBinder.setId(isId);
propertyBinder.setInheritanceStatePerClass(inheritanceStatePerClass);
propertyBinder.makePropertyValueAndBind(); propertyBinder.makePropertyValueAndBind();
} }
if (isId) { if (isId) {
@ -2105,6 +2139,7 @@ private static PropertyBinder bindComponent(
binder.setEmbedded( isComponentEmbedded ); binder.setEmbedded( isComponentEmbedded );
binder.setHolder( propertyHolder ); binder.setHolder( propertyHolder );
binder.setId( isId ); binder.setId( isId );
binder.setEntityBinder( entityBinder );
binder.setInheritanceStatePerClass( inheritanceStatePerClass ); binder.setInheritanceStatePerClass( inheritanceStatePerClass );
binder.setMappings( mappings ); binder.setMappings( mappings );
binder.makePropertyAndBind(); binder.makePropertyAndBind();
@ -2136,17 +2171,7 @@ public static Component fillComponent(
* Because it's a value type, there is no bidirectional association, hence second pass * Because it's a value type, there is no bidirectional association, hence second pass
* ordering does not matter * ordering does not matter
*/ */
Component comp = new Component( propertyHolder.getPersistentClass() ); Component comp = createComponent( propertyHolder, inferredData, isComponentEmbedded, isIdentifierMapper );
comp.setEmbedded( isComponentEmbedded );
//yuk
comp.setTable( propertyHolder.getTable() );
if ( !isIdentifierMapper ) {
comp.setComponentClassName( inferredData.getClassOrElementName() );
}
else {
comp.setComponentClassName( comp.getOwner().getClassName() );
}
comp.setNodeName( inferredData.getPropertyName() );
String subpath = BinderHelper.getPath( propertyHolder, inferredData ); String subpath = BinderHelper.getPath( propertyHolder, inferredData );
log.trace( "Binding component with path: {}", subpath ); log.trace( "Binding component with path: {}", subpath );
PropertyHolder subHolder = PropertyHolderBuilder.buildPropertyHolder( PropertyHolder subHolder = PropertyHolderBuilder.buildPropertyHolder(
@ -2202,6 +2227,22 @@ public static Component fillComponent(
return comp; return comp;
} }
public static Component createComponent(PropertyHolder propertyHolder, PropertyData inferredData, boolean isComponentEmbedded, boolean isIdentifierMapper) {
Component comp = new Component( propertyHolder.getPersistentClass() );
comp.setEmbedded( isComponentEmbedded );
//yuk
comp.setTable( propertyHolder.getTable() );
//FIXME shouldn't identifier mapper use getClassOrElementName? Need to be checked.
if ( isIdentifierMapper || ( isComponentEmbedded && inferredData.getPropertyName() == null ) ) {
comp.setComponentClassName( comp.getOwner().getClassName() );
}
else {
comp.setComponentClassName( inferredData.getClassOrElementName() );
}
comp.setNodeName( inferredData.getPropertyName() );
return comp;
}
private static void bindId( private static void bindId(
String generatorType, String generatorName, String generatorType, String generatorName,
PropertyData inferredData, Ejb3Column[] columns, PropertyHolder propertyHolder, PropertyData inferredData, Ejb3Column[] columns, PropertyHolder propertyHolder,
@ -2345,7 +2386,9 @@ private static void bindManyToOne(
String cascadeStrategy, Ejb3JoinColumn[] columns, boolean optional, String cascadeStrategy, Ejb3JoinColumn[] columns, boolean optional,
boolean ignoreNotFound, boolean cascadeOnDelete, boolean ignoreNotFound, boolean cascadeOnDelete,
XClass targetEntity, PropertyHolder propertyHolder, XClass targetEntity, PropertyHolder propertyHolder,
PropertyData inferredData, boolean unique, boolean isIdentifierMapper, boolean inSecondPass, PropertyData inferredData, boolean unique,
boolean isIdentifierMapper, boolean inSecondPass,
PropertyBinder propertyBinder,
ExtendedMappings mappings ExtendedMappings mappings
) { ) {
//All FK columns should be in the same table //All FK columns should be in the same table
@ -2399,24 +2442,26 @@ private static void bindManyToOne(
); );
} }
Ejb3Column.checkPropertyConsistency( columns, propertyHolder.getEntityName() + propertyName ); Ejb3Column.checkPropertyConsistency( columns, propertyHolder.getEntityName() + propertyName );
PropertyBinder binder = new PropertyBinder(); //PropertyBinder binder = new PropertyBinder();
binder.setName( propertyName ); propertyBinder.setName( propertyName );
binder.setValue( value ); propertyBinder.setValue( value );
//binder.setCascade(cascadeStrategy); //binder.setCascade(cascadeStrategy);
if ( isIdentifierMapper ) { if ( isIdentifierMapper ) {
binder.setInsertable( false ); propertyBinder.setInsertable( false );
binder.setUpdatable( false ); propertyBinder.setUpdatable( false );
} }
else { else {
binder.setInsertable( columns[0].isInsertable() ); propertyBinder.setInsertable( columns[0].isInsertable() );
binder.setUpdatable( columns[0].isUpdatable() ); propertyBinder.setUpdatable( columns[0].isUpdatable() );
} }
binder.setAccessType( inferredData.getDefaultAccess() ); propertyBinder.setColumns( columns );
binder.setCascade( cascadeStrategy ); propertyBinder.setAccessType( inferredData.getDefaultAccess() );
binder.setProperty( property ); propertyBinder.setCascade( cascadeStrategy );
Property prop = binder.makeProperty(); propertyBinder.setProperty( property );
propertyBinder.setXToMany( true );
Property prop = propertyBinder.makePropertyAndBind();
//composite FK columns are in the same table so its OK //composite FK columns are in the same table so its OK
propertyHolder.addProperty( prop, columns, inferredData.getDeclaringClass() ); //propertyHolder.addProperty( prop, columns, inferredData.getDeclaringClass() );
} }
protected static void defineFetchingStrategy(ToOne toOne, XProperty property) { protected static void defineFetchingStrategy(ToOne toOne, XProperty property) {
@ -2476,7 +2521,10 @@ private static void bindOneToOne(
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
PropertyData inferredData, String mappedBy, PropertyData inferredData, String mappedBy,
boolean trueOneToOne, boolean trueOneToOne,
boolean isIdentifierMapper, boolean inSecondPass, ExtendedMappings mappings boolean isIdentifierMapper,
boolean inSecondPass,
PropertyBinder propertyBinder,
ExtendedMappings mappings
) { ) {
//column.getTable() => persistentClass.getTable() //column.getTable() => persistentClass.getTable()
final String propertyName = inferredData.getPropertyName(); final String propertyName = inferredData.getPropertyName();
@ -2535,7 +2583,8 @@ private static void bindOneToOne(
bindManyToOne( bindManyToOne(
cascadeStrategy, joinColumns, optional, ignoreNotFound, cascadeOnDelete, cascadeStrategy, joinColumns, optional, ignoreNotFound, cascadeOnDelete,
targetEntity, targetEntity,
propertyHolder, inferredData, true, isIdentifierMapper, inSecondPass, mappings propertyHolder, inferredData, true, isIdentifierMapper, inSecondPass,
propertyBinder, mappings
); );
} }
} }

View File

@ -119,6 +119,11 @@ public class EntityBinder {
private boolean ignoreIdAnnotations; private boolean ignoreIdAnnotations;
private boolean cacheLazyProperty; private boolean cacheLazyProperty;
private AccessType propertyAccessType = AccessType.DEFAULT; private AccessType propertyAccessType = AccessType.DEFAULT;
private boolean wrapIdsInEmbeddedComponents;
public boolean wrapIdsInEmbeddedComponents() {
return wrapIdsInEmbeddedComponents;
}
/** /**
* Use as a fake one for Collection of elements * Use as a fake one for Collection of elements
@ -413,6 +418,11 @@ public void setWhere(Where whereAnn) {
} }
} }
public void setWrapIdsInEmbeddedComponents(boolean wrapIdsInEmbeddedComponents) {
this.wrapIdsInEmbeddedComponents = wrapIdsInEmbeddedComponents;
}
private static class EntityTableObjectNameSource implements ObjectNameSource { private static class EntityTableObjectNameSource implements ObjectNameSource {
private final String explicitName; private final String explicitName;
private final String logicalName; private final String logicalName;

View File

@ -40,11 +40,14 @@
import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.cfg.AccessType; import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotationBinder;
import org.hibernate.cfg.BinderHelper; import org.hibernate.cfg.BinderHelper;
import org.hibernate.cfg.Ejb3Column; import org.hibernate.cfg.Ejb3Column;
import org.hibernate.cfg.ExtendedMappings; import org.hibernate.cfg.ExtendedMappings;
import org.hibernate.cfg.InheritanceState; import org.hibernate.cfg.InheritanceState;
import org.hibernate.cfg.PropertyHolder; import org.hibernate.cfg.PropertyHolder;
import org.hibernate.cfg.PropertyPreloadedData;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.KeyValue; import org.hibernate.mapping.KeyValue;
import org.hibernate.mapping.Property; import org.hibernate.mapping.Property;
import org.hibernate.mapping.PropertyGeneration; import org.hibernate.mapping.PropertyGeneration;
@ -73,15 +76,21 @@ public class PropertyBinder {
private XClass declaringClass; private XClass declaringClass;
private boolean declaringClassSet; private boolean declaringClassSet;
private boolean embedded; private boolean embedded;
private EntityBinder entityBinder;
private boolean isXToMany;
public void setEmbedded(boolean embedded) { public void setEmbedded(boolean embedded) {
this.embedded = embedded; this.embedded = embedded;
} }
public void setEntityBinder(EntityBinder entityBinder) {
this.entityBinder = entityBinder;
}
/* /*
* property can be null * property can be null
* prefer propertyName to property.getName() since some are overloaded * prefer propertyName to property.getName() since some are overloaded
*/ */
private XProperty property; private XProperty property;
private XClass returnedClass; private XClass returnedClass;
private boolean isId; private boolean isId;
@ -185,27 +194,45 @@ public Property makePropertyValueAndBind() {
return bind( makePropertyAndValue() ); return bind( makePropertyAndValue() );
} }
public void setXToMany(boolean xToMany) {
this.isXToMany = xToMany;
}
private Property bind(Property prop) { private Property bind(Property prop) {
if (isId) { if (isId) {
final RootClass rootClass = ( RootClass ) holder.getPersistentClass(); final RootClass rootClass = ( RootClass ) holder.getPersistentClass();
rootClass.setIdentifier( ( KeyValue ) getValue() ); //if an xToMany, it as to be wrapped today.
//FIXME this pose a problem as the PK is the class instead of the associated class which is not really compliant with the spec
if (embedded) { if ( isXToMany || entityBinder.wrapIdsInEmbeddedComponents() ) {
rootClass.setEmbeddedIdentifier( true ); Component identifier = (Component) rootClass.getIdentifier();
if (identifier == null) {
identifier = AnnotationBinder.createComponent( holder, new PropertyPreloadedData(null, null, null), true, false );
rootClass.setIdentifier( identifier );
identifier.setNullValue( "undefined" );
rootClass.setEmbeddedIdentifier( true );
}
//FIXME is it good enough?
identifier.addProperty( prop );
} }
else { else {
rootClass.setIdentifierProperty( prop ); rootClass.setIdentifier( ( KeyValue ) getValue() );
final org.hibernate.mapping.MappedSuperclass superclass = BinderHelper.getMappedSuperclassOrNull( if (embedded) {
declaringClass, rootClass.setEmbeddedIdentifier( true );
inheritanceStatePerClass,
mappings
);
if (superclass != null) {
superclass.setDeclaredIdentifierProperty(prop);
} }
else { else {
//we know the property is on the actual entity rootClass.setIdentifierProperty( prop );
rootClass.setDeclaredIdentifierProperty( prop ); final org.hibernate.mapping.MappedSuperclass superclass = BinderHelper.getMappedSuperclassOrNull(
declaringClass,
inheritanceStatePerClass,
mappings
);
if (superclass != null) {
superclass.setDeclaredIdentifierProperty(prop);
}
else {
//we know the property is on the actual entity
rootClass.setDeclaredIdentifierProperty( prop );
}
} }
} }
} }

View File

@ -1,4 +1,4 @@
// $Id:$ // $Id$
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
@ -24,6 +24,8 @@
*/ */
package org.hibernate.cfg.annotations; package org.hibernate.cfg.annotations;
import java.util.Date;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -34,7 +36,7 @@ public class Version {
private static Logger log = LoggerFactory.getLogger( Version.class ); private static Logger log = LoggerFactory.getLogger( Version.class );
public static String getVersionString() { public static String getVersionString() {
return "[WORKING]"; return "[WORKING]-1";
} }
static { static {

View File

@ -0,0 +1,25 @@
package org.hibernate.test.annotations.derivedidentities.e1.c;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
/**
* @author Emmanuel Bernard
*/
@Entity
public class Dependent implements Serializable {
@Id
String name;
@Id
//@JoinColumn(name = "FK")
// id attribute mapped by join column default
@ManyToOne
Employee emp;
}

View File

@ -0,0 +1,46 @@
package org.hibernate.test.annotations.derivedidentities.e1.c;
import org.hibernate.Session;
import org.hibernate.test.annotations.TestCase;
import org.hibernate.test.util.SchemaUtil;
/**
* @author Emmanuel Bernard
*/
public class DerivedIdentitySimpleParentEmbeddedDepTest extends TestCase {
public void testManyToOne() throws Exception {
assertTrue( SchemaUtil.isColumnPresent( "Dependent", "emp_empId", getCfg() ) );
assertTrue( ! SchemaUtil.isColumnPresent( "Dependent", "empPK", getCfg() ) );
Employee e = new Employee();
e.empId = 1;
e.empName = "Emmanuel";
Session s = openSession( );
s.getTransaction().begin();
s.persist( e );
Dependent d = new Dependent();
d.emp = e;
d.name = "Doggy";
s.persist( d );
s.flush();
s.clear();
d = getDerivedClassById( e, s, Dependent.class, d.name );
assertEquals( e.empId, d.emp.empId );
s.getTransaction().rollback();
s.close();
}
private <T> T getDerivedClassById(Employee e, Session s, Class<T> clazz, String name) {
return ( T )
s.createQuery( "from " + clazz.getName() + " d where d.name = :name and d.emp.empId = :empId")
.setParameter( "empId", e.empId ).setParameter( "name", name ).uniqueResult();
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Dependent.class,
Employee.class
};
}
}

View File

@ -0,0 +1,14 @@
package org.hibernate.test.annotations.derivedidentities.e1.c;
import javax.persistence.Entity;
import javax.persistence.Id;
/**
* @author Emmanuel Bernard
*/
@Entity
public class Employee {
@Id
long empId;
String empName;
}

View File

@ -0,0 +1,78 @@
package org.hibernate.test.annotations.derivedidentities.e4.a;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.test.annotations.TestCase;
import org.hibernate.test.util.SchemaUtil;
/**
* @author Emmanuel Bernard
*/
public class DerivedIdentitySimpleParentSimpleDepTest extends TestCase {
public void testOneToOneExplicitJoinColumn() throws Exception {
assertTrue( SchemaUtil.isColumnPresent( "MedicalHistory", "FK", getCfg() ) );
assertTrue( ! SchemaUtil.isColumnPresent( "MedicalHistory", "id", getCfg() ) );
Person e = new Person();
e.ssn = "aaa";
Session s = openSession( );
s.getTransaction().begin();
s.persist( e );
MedicalHistory d = new MedicalHistory();
d.patient = e;
s.persist( d );
s.flush();
s.clear();
final Class<MedicalHistory> clazz = MedicalHistory.class;
d = getDerivedClassById( e, s, clazz );
assertEquals( e.ssn, d.patient.ssn );
d.lastupdate = new Date();
s.flush();
s.clear();
d = getDerivedClassById( e, s, clazz );
assertNotNull( d.lastupdate );
s.getTransaction().rollback();
s.close();
}
private <T> T getDerivedClassById(Person e, Session s, Class<T> clazz) {
return ( T )
s.createQuery( "from " + clazz.getName() + " mh where mh.patient.ssn = :ssn")
.setParameter( "ssn", e.ssn ).uniqueResult();
}
public void testManyToOneExplicitJoinColumn() throws Exception {
assertTrue( SchemaUtil.isColumnPresent( "FinancialHistory", "patient_ssn", getCfg() ) );
assertTrue( ! SchemaUtil.isColumnPresent( "FinancialHistory", "id", getCfg() ) );
Person e = new Person();
e.ssn = "aaa";
Session s = openSession( );
s.getTransaction().begin();
s.persist( e );
FinancialHistory d = new FinancialHistory();
d.patient = e;
s.persist( d );
s.flush();
s.clear();
d = getDerivedClassById(e, s, FinancialHistory.class);
assertEquals( e.ssn, d.patient.ssn );
d.lastupdate = new Date();
s.flush();
s.clear();
d = getDerivedClassById(e, s, FinancialHistory.class);
assertNotNull( d.lastupdate );
s.getTransaction().rollback();
s.close();
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
MedicalHistory.class,
Simple.class,
Person.class,
FinancialHistory.class
};
}
}

View File

@ -0,0 +1,28 @@
package org.hibernate.test.annotations.derivedidentities.e4.a;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapsId;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
/**
* @author Emmanuel Bernard
*/
@Entity
public class FinancialHistory implements Serializable {
@Temporal(TemporalType.DATE)
Date lastupdate;
@Id
//@JoinColumn(name = "FK")
@ManyToOne
Person patient;
}

View File

@ -0,0 +1,27 @@
package org.hibernate.test.annotations.derivedidentities.e4.a;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapsId;
import javax.persistence.OneToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
/**
* @author Emmanuel Bernard
*/
@Entity
public class MedicalHistory implements Serializable {
@Temporal(TemporalType.DATE)
Date lastupdate;
@Id
@JoinColumn(name = "FK")
@OneToOne
Person patient;
}

View File

@ -0,0 +1,14 @@
package org.hibernate.test.annotations.derivedidentities.e4.a;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
/**
* @author Emmanuel Bernard
*/
@Entity
public class Person {
@Id
String ssn;
}

View File

@ -0,0 +1,17 @@
package org.hibernate.test.annotations.derivedidentities.e4.a;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
/**
* @author Emmanuel Bernard
*/
@Entity
public class Simple
implements Serializable {
@Id
String ssn;
@Id
String name;
}