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:
parent
671d9db8e2
commit
d00f7efb30
|
@ -625,10 +625,10 @@ public final class AnnotationBinder {
|
|||
HashMap<String, IdGenerator> classGenerators = buildLocalGenerators( clazzToProcess, mappings );
|
||||
|
||||
// check properties
|
||||
List<PropertyData> elements =
|
||||
getElementsToProcess(
|
||||
persistentClass, clazzToProcess, inheritanceStatePerClass, entityBinder, mappings
|
||||
);
|
||||
final ElementsToProcess elementsToProcess = getElementsToProcess(
|
||||
persistentClass, clazzToProcess, inheritanceStatePerClass, entityBinder, mappings
|
||||
);
|
||||
|
||||
final boolean subclassAndSingleTableStrategy = inheritanceState.getType() == InheritanceType.SINGLE_TABLE
|
||||
&& inheritanceState.hasParents();
|
||||
//process idclass if any
|
||||
|
@ -674,7 +674,9 @@ public final class AnnotationBinder {
|
|||
isComponent,
|
||||
propertyAccessor, entityBinder,
|
||||
true,
|
||||
false, mappings, inheritanceStatePerClass
|
||||
false,
|
||||
mappings,
|
||||
inheritanceStatePerClass
|
||||
);
|
||||
inferredData = new PropertyPreloadedData(
|
||||
propertyAccessor, "_identifierMapper", compositeClass
|
||||
|
@ -683,9 +685,11 @@ public final class AnnotationBinder {
|
|||
propertyHolder,
|
||||
inferredData,
|
||||
baseInferredData,
|
||||
propertyAccessor, false,
|
||||
propertyAccessor,
|
||||
false,
|
||||
entityBinder,
|
||||
true, true,
|
||||
true,
|
||||
true,
|
||||
false, mappings, inheritanceStatePerClass
|
||||
);
|
||||
entityBinder.setIgnoreIdAnnotations( ignoreIdAnnotations );
|
||||
|
@ -720,8 +724,11 @@ public final class AnnotationBinder {
|
|||
idProperties.add( ( (Property) properties.next() ).getName() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
entityBinder.setWrapIdsInEmbeddedComponents( elementsToProcess.getIdPropertyCount() > 1 );
|
||||
}
|
||||
Set<String> missingIdProperties = new HashSet<String>( idProperties );
|
||||
for (PropertyData propertyAnnotatedElement : elements) {
|
||||
for (PropertyData propertyAnnotatedElement : elementsToProcess.getElements() ) {
|
||||
String propertyName = propertyAnnotatedElement.getPropertyName();
|
||||
if ( !idProperties.contains( propertyName ) ) {
|
||||
processElementAnnotations(
|
||||
|
@ -979,7 +986,7 @@ public final class AnnotationBinder {
|
|||
* Get the annotated elements, guessing the access type from @Id or @EmbeddedId presence.
|
||||
* Change EntityBinder by side effect
|
||||
*/
|
||||
private static List<PropertyData> getElementsToProcess(
|
||||
private static ElementsToProcess getElementsToProcess(
|
||||
PersistentClass persistentClass, XClass clazzToProcess,
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
EntityBinder entityBinder, ExtendedMappings mappings
|
||||
|
@ -996,21 +1003,39 @@ public final class AnnotationBinder {
|
|||
|
||||
List<PropertyData> elements = new ArrayList<PropertyData>();
|
||||
int deep = classesToProcess.size();
|
||||
boolean hasIdentifier = false;
|
||||
int idPropertyCount = 0;
|
||||
|
||||
for ( int index = 0; index < deep; index++ ) {
|
||||
PropertyContainer properyContainer = new PropertyContainer( classesToProcess.get( index ), clazzToProcess );
|
||||
boolean currentHasIdentifier = addElementsOfClass( elements, accessType, properyContainer, mappings );
|
||||
hasIdentifier = hasIdentifier || currentHasIdentifier;
|
||||
PropertyContainer propertyContainer = new PropertyContainer( classesToProcess.get( index ), clazzToProcess );
|
||||
int currentIdPropertyCount = addElementsOfClass( elements, accessType, propertyContainer, mappings );
|
||||
idPropertyCount += currentIdPropertyCount;
|
||||
}
|
||||
|
||||
entityBinder.setPropertyAccessType( accessType );
|
||||
|
||||
if ( !hasIdentifier && !inheritanceState.hasParents() ) {
|
||||
if ( idPropertyCount == 0 && !inheritanceState.hasParents() ) {
|
||||
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) {
|
||||
|
@ -1207,13 +1232,13 @@ public final class AnnotationBinder {
|
|||
* strategy is used
|
||||
* @param propertyContainer Metadata about a class and its properties
|
||||
* @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.
|
||||
*/
|
||||
private static boolean addElementsOfClass(
|
||||
private static int addElementsOfClass(
|
||||
List<PropertyData> elements, AccessType defaultAccessType, PropertyContainer propertyContainer, ExtendedMappings mappings
|
||||
) {
|
||||
boolean hasIdentifier = false;
|
||||
int idPropertyCounter = 0;
|
||||
AccessType accessType = defaultAccessType;
|
||||
|
||||
if ( propertyContainer.hasExplicitAccessStrategy() ) {
|
||||
|
@ -1223,21 +1248,21 @@ public final class AnnotationBinder {
|
|||
propertyContainer.assertTypesAreResolvable( accessType );
|
||||
Collection<XProperty> properties = propertyContainer.getProperties( accessType );
|
||||
for ( XProperty p : properties ) {
|
||||
final boolean currentHasIdentifier = addProperty(
|
||||
final int currentIdPropertyCounter = addProperty(
|
||||
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,
|
||||
String propertyAccessor, ExtendedMappings mappings
|
||||
) {
|
||||
final XClass declaringClass = propertyContainer.getDeclaringClass();
|
||||
final XClass entity = propertyContainer.getEntityAtStake();
|
||||
boolean hasIdentifier;
|
||||
int idPropertyCounter = 0;
|
||||
PropertyData propertyAnnotatedElement = new PropertyInferredData(
|
||||
declaringClass, property, propertyAccessor,
|
||||
mappings.getReflectionManager() );
|
||||
|
@ -1249,17 +1274,16 @@ public final class AnnotationBinder {
|
|||
final XAnnotatedElement element = propertyAnnotatedElement.getProperty();
|
||||
if ( element.isAnnotationPresent( Id.class ) || element.isAnnotationPresent( EmbeddedId.class ) ) {
|
||||
annElts.add( 0, propertyAnnotatedElement );
|
||||
hasIdentifier = true;
|
||||
idPropertyCounter++;
|
||||
}
|
||||
else {
|
||||
annElts.add( propertyAnnotatedElement );
|
||||
hasIdentifier = false;
|
||||
}
|
||||
if ( element.isAnnotationPresent( MapsId.class ) ) {
|
||||
mappings.addPropertyAnnotatedWithMapsId( entity, propertyAnnotatedElement );
|
||||
}
|
||||
|
||||
return hasIdentifier;
|
||||
return idPropertyCounter;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1361,9 +1385,28 @@ public final class AnnotationBinder {
|
|||
|
||||
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() &&
|
||||
( property.isAnnotationPresent( Id.class )
|
||||
|| property.isAnnotationPresent( EmbeddedId.class ) );
|
||||
propertyBinder.setId( isId );
|
||||
|
||||
if ( property.isAnnotationPresent( Version.class ) ) {
|
||||
if ( isIdentifierMapper ) {
|
||||
throw new AnnotationException(
|
||||
|
@ -1384,19 +1427,14 @@ public final class AnnotationBinder {
|
|||
}
|
||||
log.trace( "{} is a version property", inferredData.getPropertyName() );
|
||||
RootClass rootClass = (RootClass) propertyHolder.getPersistentClass();
|
||||
PropertyBinder propBinder = new PropertyBinder();
|
||||
propBinder.setName( inferredData.getPropertyName() );
|
||||
propBinder.setReturnedClassName( inferredData.getTypeName() );
|
||||
propBinder.setLazy( false );
|
||||
propBinder.setAccessType( inferredData.getDefaultAccess() );
|
||||
propBinder.setColumns( columns );
|
||||
propBinder.setHolder( propertyHolder ); //PropertyHolderBuilder.buildPropertyHolder(rootClass)
|
||||
propBinder.setProperty( property );
|
||||
propBinder.setReturnedClass( inferredData.getPropertyClass() );
|
||||
propBinder.setMappings( mappings );
|
||||
propBinder.setDeclaringClass( inferredData.getDeclaringClass() );
|
||||
Property prop = propBinder.makePropertyValueAndBind();
|
||||
propBinder.getSimpleValueBinder().setVersion(true);
|
||||
// PropertyBinder propBinder = new PropertyBinder();
|
||||
// propBinder.setName( inferredData.getPropertyName() );
|
||||
// propBinder.setReturnedClassName( inferredData.getTypeName() );
|
||||
// propBinder.setLazy( false );
|
||||
// propBinder.setAccessType( inferredData.getDefaultAccess() );
|
||||
propertyBinder.setColumns( columns );
|
||||
Property prop = propertyBinder.makePropertyValueAndBind();
|
||||
propertyBinder.getSimpleValueBinder().setVersion(true);
|
||||
rootClass.setVersion( prop );
|
||||
|
||||
//If version is on a mapped superclass, update the mapping
|
||||
|
@ -1451,7 +1489,8 @@ public final class AnnotationBinder {
|
|||
ignoreNotFound, onDeleteCascade,
|
||||
ToOneBinder.getTargetEntity( inferredData, mappings ),
|
||||
propertyHolder,
|
||||
inferredData, false, isIdentifierMapper, inSecondPass, mappings
|
||||
inferredData, false, isIdentifierMapper,
|
||||
inSecondPass, propertyBinder, mappings
|
||||
);
|
||||
}
|
||||
else if ( property.isAnnotationPresent( OneToOne.class ) ) {
|
||||
|
@ -1489,7 +1528,13 @@ public final class AnnotationBinder {
|
|||
ignoreNotFound, onDeleteCascade,
|
||||
ToOneBinder.getTargetEntity( inferredData, mappings ),
|
||||
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 ) ) {
|
||||
|
@ -1793,7 +1838,7 @@ public final class AnnotationBinder {
|
|||
isComponent = property.isAnnotationPresent( Embedded.class )
|
||||
|| property.isAnnotationPresent( EmbeddedId.class )
|
||||
|| returnedClass.isAnnotationPresent( Embeddable.class );
|
||||
PropertyBinder propertyBinder;
|
||||
|
||||
if ( isComponent ) {
|
||||
AccessType propertyAccessor = entityBinder.getPropertyAccessor( property );
|
||||
propertyBinder = bindComponent(
|
||||
|
@ -1835,23 +1880,12 @@ public final class AnnotationBinder {
|
|||
mappings );
|
||||
}
|
||||
|
||||
propertyBinder = new PropertyBinder();
|
||||
propertyBinder.setName( inferredData.getPropertyName() );
|
||||
propertyBinder.setReturnedClassName( inferredData.getTypeName() );
|
||||
propertyBinder.setLazy( lazy );
|
||||
propertyBinder.setAccessType( inferredData.getDefaultAccess() );
|
||||
propertyBinder.setColumns( columns );
|
||||
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.setId(isId);
|
||||
propertyBinder.setInheritanceStatePerClass(inheritanceStatePerClass);
|
||||
// if ( isIdentifierMapper ) {
|
||||
// propertyBinder.setInsertable( false );
|
||||
// propertyBinder.setUpdatable( false );
|
||||
// }
|
||||
propertyBinder.makePropertyValueAndBind();
|
||||
}
|
||||
if (isId) {
|
||||
|
@ -2105,6 +2139,7 @@ public final class AnnotationBinder {
|
|||
binder.setEmbedded( isComponentEmbedded );
|
||||
binder.setHolder( propertyHolder );
|
||||
binder.setId( isId );
|
||||
binder.setEntityBinder( entityBinder );
|
||||
binder.setInheritanceStatePerClass( inheritanceStatePerClass );
|
||||
binder.setMappings( mappings );
|
||||
binder.makePropertyAndBind();
|
||||
|
@ -2136,17 +2171,7 @@ public final class AnnotationBinder {
|
|||
* Because it's a value type, there is no bidirectional association, hence second pass
|
||||
* ordering does not matter
|
||||
*/
|
||||
Component comp = new Component( propertyHolder.getPersistentClass() );
|
||||
comp.setEmbedded( isComponentEmbedded );
|
||||
//yuk
|
||||
comp.setTable( propertyHolder.getTable() );
|
||||
if ( !isIdentifierMapper ) {
|
||||
comp.setComponentClassName( inferredData.getClassOrElementName() );
|
||||
}
|
||||
else {
|
||||
comp.setComponentClassName( comp.getOwner().getClassName() );
|
||||
}
|
||||
comp.setNodeName( inferredData.getPropertyName() );
|
||||
Component comp = createComponent( propertyHolder, inferredData, isComponentEmbedded, isIdentifierMapper );
|
||||
String subpath = BinderHelper.getPath( propertyHolder, inferredData );
|
||||
log.trace( "Binding component with path: {}", subpath );
|
||||
PropertyHolder subHolder = PropertyHolderBuilder.buildPropertyHolder(
|
||||
|
@ -2202,6 +2227,22 @@ public final class AnnotationBinder {
|
|||
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(
|
||||
String generatorType, String generatorName,
|
||||
PropertyData inferredData, Ejb3Column[] columns, PropertyHolder propertyHolder,
|
||||
|
@ -2345,7 +2386,9 @@ public final class AnnotationBinder {
|
|||
String cascadeStrategy, Ejb3JoinColumn[] columns, boolean optional,
|
||||
boolean ignoreNotFound, boolean cascadeOnDelete,
|
||||
XClass targetEntity, PropertyHolder propertyHolder,
|
||||
PropertyData inferredData, boolean unique, boolean isIdentifierMapper, boolean inSecondPass,
|
||||
PropertyData inferredData, boolean unique,
|
||||
boolean isIdentifierMapper, boolean inSecondPass,
|
||||
PropertyBinder propertyBinder,
|
||||
ExtendedMappings mappings
|
||||
) {
|
||||
//All FK columns should be in the same table
|
||||
|
@ -2399,24 +2442,26 @@ public final class AnnotationBinder {
|
|||
);
|
||||
}
|
||||
Ejb3Column.checkPropertyConsistency( columns, propertyHolder.getEntityName() + propertyName );
|
||||
PropertyBinder binder = new PropertyBinder();
|
||||
binder.setName( propertyName );
|
||||
binder.setValue( value );
|
||||
//PropertyBinder binder = new PropertyBinder();
|
||||
propertyBinder.setName( propertyName );
|
||||
propertyBinder.setValue( value );
|
||||
//binder.setCascade(cascadeStrategy);
|
||||
if ( isIdentifierMapper ) {
|
||||
binder.setInsertable( false );
|
||||
binder.setUpdatable( false );
|
||||
propertyBinder.setInsertable( false );
|
||||
propertyBinder.setUpdatable( false );
|
||||
}
|
||||
else {
|
||||
binder.setInsertable( columns[0].isInsertable() );
|
||||
binder.setUpdatable( columns[0].isUpdatable() );
|
||||
propertyBinder.setInsertable( columns[0].isInsertable() );
|
||||
propertyBinder.setUpdatable( columns[0].isUpdatable() );
|
||||
}
|
||||
binder.setAccessType( inferredData.getDefaultAccess() );
|
||||
binder.setCascade( cascadeStrategy );
|
||||
binder.setProperty( property );
|
||||
Property prop = binder.makeProperty();
|
||||
propertyBinder.setColumns( columns );
|
||||
propertyBinder.setAccessType( inferredData.getDefaultAccess() );
|
||||
propertyBinder.setCascade( cascadeStrategy );
|
||||
propertyBinder.setProperty( property );
|
||||
propertyBinder.setXToMany( true );
|
||||
Property prop = propertyBinder.makePropertyAndBind();
|
||||
//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) {
|
||||
|
@ -2476,7 +2521,10 @@ public final class AnnotationBinder {
|
|||
PropertyHolder propertyHolder,
|
||||
PropertyData inferredData, String mappedBy,
|
||||
boolean trueOneToOne,
|
||||
boolean isIdentifierMapper, boolean inSecondPass, ExtendedMappings mappings
|
||||
boolean isIdentifierMapper,
|
||||
boolean inSecondPass,
|
||||
PropertyBinder propertyBinder,
|
||||
ExtendedMappings mappings
|
||||
) {
|
||||
//column.getTable() => persistentClass.getTable()
|
||||
final String propertyName = inferredData.getPropertyName();
|
||||
|
@ -2535,7 +2583,8 @@ public final class AnnotationBinder {
|
|||
bindManyToOne(
|
||||
cascadeStrategy, joinColumns, optional, ignoreNotFound, cascadeOnDelete,
|
||||
targetEntity,
|
||||
propertyHolder, inferredData, true, isIdentifierMapper, inSecondPass, mappings
|
||||
propertyHolder, inferredData, true, isIdentifierMapper, inSecondPass,
|
||||
propertyBinder, mappings
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,6 +119,11 @@ public class EntityBinder {
|
|||
private boolean ignoreIdAnnotations;
|
||||
private boolean cacheLazyProperty;
|
||||
private AccessType propertyAccessType = AccessType.DEFAULT;
|
||||
private boolean wrapIdsInEmbeddedComponents;
|
||||
|
||||
public boolean wrapIdsInEmbeddedComponents() {
|
||||
return wrapIdsInEmbeddedComponents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use as a fake one for Collection of elements
|
||||
|
@ -413,6 +418,11 @@ public class EntityBinder {
|
|||
}
|
||||
}
|
||||
|
||||
public void setWrapIdsInEmbeddedComponents(boolean wrapIdsInEmbeddedComponents) {
|
||||
this.wrapIdsInEmbeddedComponents = wrapIdsInEmbeddedComponents;
|
||||
}
|
||||
|
||||
|
||||
private static class EntityTableObjectNameSource implements ObjectNameSource {
|
||||
private final String explicitName;
|
||||
private final String logicalName;
|
||||
|
|
|
@ -40,11 +40,14 @@ import org.hibernate.annotations.common.AssertionFailure;
|
|||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.cfg.AccessType;
|
||||
import org.hibernate.cfg.AnnotationBinder;
|
||||
import org.hibernate.cfg.BinderHelper;
|
||||
import org.hibernate.cfg.Ejb3Column;
|
||||
import org.hibernate.cfg.ExtendedMappings;
|
||||
import org.hibernate.cfg.InheritanceState;
|
||||
import org.hibernate.cfg.PropertyHolder;
|
||||
import org.hibernate.cfg.PropertyPreloadedData;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.PropertyGeneration;
|
||||
|
@ -73,15 +76,21 @@ public class PropertyBinder {
|
|||
private XClass declaringClass;
|
||||
private boolean declaringClassSet;
|
||||
private boolean embedded;
|
||||
private EntityBinder entityBinder;
|
||||
private boolean isXToMany;
|
||||
|
||||
public void setEmbedded(boolean embedded) {
|
||||
this.embedded = embedded;
|
||||
}
|
||||
|
||||
public void setEntityBinder(EntityBinder entityBinder) {
|
||||
this.entityBinder = entityBinder;
|
||||
}
|
||||
|
||||
/*
|
||||
* property can be null
|
||||
* prefer propertyName to property.getName() since some are overloaded
|
||||
*/
|
||||
* property can be null
|
||||
* prefer propertyName to property.getName() since some are overloaded
|
||||
*/
|
||||
private XProperty property;
|
||||
private XClass returnedClass;
|
||||
private boolean isId;
|
||||
|
@ -185,27 +194,45 @@ public class PropertyBinder {
|
|||
return bind( makePropertyAndValue() );
|
||||
}
|
||||
|
||||
public void setXToMany(boolean xToMany) {
|
||||
this.isXToMany = xToMany;
|
||||
}
|
||||
|
||||
private Property bind(Property prop) {
|
||||
if (isId) {
|
||||
final RootClass rootClass = ( RootClass ) holder.getPersistentClass();
|
||||
rootClass.setIdentifier( ( KeyValue ) getValue() );
|
||||
|
||||
if (embedded) {
|
||||
rootClass.setEmbeddedIdentifier( true );
|
||||
//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 ( isXToMany || entityBinder.wrapIdsInEmbeddedComponents() ) {
|
||||
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 {
|
||||
rootClass.setIdentifierProperty( prop );
|
||||
final org.hibernate.mapping.MappedSuperclass superclass = BinderHelper.getMappedSuperclassOrNull(
|
||||
declaringClass,
|
||||
inheritanceStatePerClass,
|
||||
mappings
|
||||
);
|
||||
if (superclass != null) {
|
||||
superclass.setDeclaredIdentifierProperty(prop);
|
||||
rootClass.setIdentifier( ( KeyValue ) getValue() );
|
||||
if (embedded) {
|
||||
rootClass.setEmbeddedIdentifier( true );
|
||||
}
|
||||
else {
|
||||
//we know the property is on the actual entity
|
||||
rootClass.setDeclaredIdentifierProperty( prop );
|
||||
rootClass.setIdentifierProperty( 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// $Id:$
|
||||
// $Id$
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
|
@ -24,6 +24,8 @@
|
|||
*/
|
||||
package org.hibernate.cfg.annotations;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -34,7 +36,7 @@ public class Version {
|
|||
private static Logger log = LoggerFactory.getLogger( Version.class );
|
||||
|
||||
public static String getVersionString() {
|
||||
return "[WORKING]";
|
||||
return "[WORKING]-1";
|
||||
}
|
||||
|
||||
static {
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue