HHH-7843 : Add support for one-to-one to new metamodel

This commit is contained in:
Gail Badner 2013-03-29 01:02:55 -07:00
parent 75f08b58ee
commit 7e1b94185d
47 changed files with 345 additions and 152 deletions

View File

@ -252,10 +252,11 @@ public class Binder {
public void bindEntityHierarchies() {
applyToAllEntityHierarchies( resolveAssociationSourcesExecutor() );
bindEntityHierarchiesExcludingNonIdAttributeBindings();
// cannot resolve associations until after entity identifiers are defined.
applyToAllEntityHierarchies( resolveAssociationSourcesExecutor() );
applyToAllEntityHierarchies( bindSingularAttributesExecutor( SingularAttributeSource.Nature.COMPOSITE ) );
// bind singular attributes
@ -345,8 +346,23 @@ public class Binder {
}
}
for ( EntityHierarchy entityHierarchy : unresolvedEntityHierarchies ) {
entityHierarchyHelper.applyToEntityHierarchy( entityHierarchy, rootEntityCallback, subEntityCallback );
int oldSize = Integer.MAX_VALUE;
while( !unresolvedEntityHierarchies.isEmpty() && unresolvedEntityHierarchies.size() < oldSize ) {
oldSize = unresolvedEntityHierarchies.size();
for ( Iterator<EntityHierarchy> it = unresolvedEntityHierarchies.iterator(); it.hasNext(); ) {
final EntityHierarchy entityHierarchy = it.next();
try {
entityHierarchyHelper.applyToEntityHierarchy( entityHierarchy, rootEntityCallback, subEntityCallback );
// succeeded, so the entityHierarchy is no longer unresolved.
it.remove();
}
catch (Exception ex) {
// to nothing;
}
}
}
if ( ! unresolvedEntityHierarchies.isEmpty() ) {
throw new IllegalStateException( "could not resolve all EntityHierarchies." );
}
}
@ -390,7 +406,7 @@ public class Binder {
return new LocalBindingContextExecutor() {
@Override
public void execute(LocalBindingContextExecutionContext bindingContextContext) {
sourceIndex.resolveAssociationSources( bindingContextContext.getEntitySource().getEntityName() );
sourceIndex.resolveAssociationSources( bindingContextContext.getEntityBinding() );
}
};
}
@ -1502,23 +1518,25 @@ public class Binder {
toOneAttributeBindingContext
);
if ( attributeSource.getForeignKeyDirection() == ForeignKeyDirection.FROM_PARENT ) {
List<RelationalValueBinding> foreignKeyRelationalValueBindings =
attributeBinding
.getContainer()
.seekEntityBinding()
.getHierarchyDetails()
.getEntityIdentifier()
.getAttributeBinding()
.getRelationalValueBindings();
List<Column> foreignKeyColumns =
attributeBinding.getContainer().getPrimaryTable().getPrimaryKey().getColumns();
//List<RelationalValueBinding> foreignKeyRelationalValueBindings =
// attributeBinding
// .getContainer()
// .seekEntityBinding()
// .getHierarchyDetails()
// .getEntityIdentifier()
// .getAttributeBinding()
// .getRelationalValueBindings();
final List<Column> targetColumns = determineForeignKeyTargetColumns(
attributeBinding.getReferencedEntityBinding(),
attributeSource
);
locateOrCreateForeignKey(
foreignKeyHelper.locateOrCreateForeignKey(
quotedIdentifier( attributeSource.getExplicitForeignKeyName() ),
foreignKeyRelationalValueBindings.get( 0 ).getTable(),
foreignKeyRelationalValueBindings,
attributeBinding.getContainer().getPrimaryTable(),// foreignKeyRelationalValueBindings.get( 0 ).getTable(),
foreignKeyColumns, // foreignKeyRelationalValueBindings,
determineForeignKeyTargetTable( attributeBinding.getReferencedEntityBinding(), attributeSource ),
targetColumns
);
@ -2083,8 +2101,12 @@ public class Binder {
)
);
if ( elementSource.isUnique() ) {
<<<<<<< HEAD
UniqueKey uk = collectionTable.getOrCreateUniqueKey( StringHelper.randomFixedLengthHex(
UniqueKey.GENERATED_NAME_PREFIX ) );
=======
// TODO: this should create a unique constrraint instead of marking each individual column unique.
>>>>>>> HHH-7843 : Add support for one-to-one to new metamodel
for ( RelationalValueBinding relationalValueBinding : elementBinding.getRelationalValueBindings() ) {
if ( ! relationalValueBinding.isDerived() ) {
uk.addColumn( (Column) relationalValueBinding.getValue() );

View File

@ -25,6 +25,7 @@ package org.hibernate.metamodel.internal;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -34,6 +35,8 @@ import org.jboss.logging.Logger;
import org.hibernate.AssertionFailure;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.source.AggregatedCompositeIdentifierSource;
import org.hibernate.metamodel.spi.source.AttributeSource;
import org.hibernate.metamodel.spi.source.ComponentAttributeSource;
@ -45,6 +48,8 @@ import org.hibernate.metamodel.spi.source.PluralAttributeSource;
import org.hibernate.metamodel.spi.source.RootEntitySource;
import org.hibernate.metamodel.spi.source.SimpleIdentifierSource;
import org.hibernate.metamodel.spi.source.SingularAttributeSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSourceNatureResolver;
/**
* @author Gail Badner
@ -69,8 +74,8 @@ public class SourceIndex {
indexAttributes( entitySourceIndex );
}
public void resolveAssociationSources(String entityName) {
entitySourceIndexByEntityName.get( entityName ).resolveAssociationSources();
public void resolveAssociationSources(EntityBinding entityBinding) {
entitySourceIndexByEntityName.get( entityBinding.getEntityName() ).resolveAssociationSources( entityBinding );
}
public Map<AttributeSourceKey, SingularAttributeSource> getSingularAttributeSources(
@ -283,16 +288,24 @@ public class SourceIndex {
String pathBase,
SingularAttributeSource attributeSource,
boolean isInIdentifier) {
final AttributeSourceKey attributeSourceKey =
new AttributeSourceKey( entitySource.getEntityName(), pathBase, attributeSource.getName() );
final Map<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>> map;
if ( isInIdentifier ) {
map = identifierAttributeSourcesByNature;
}
else {
map = singularAttributeSourcesByNature;
}
indexSingularAttributeSource(
entitySource.getEntityName(),
pathBase,
attributeSourceKey,
attributeSource,
isInIdentifier ? identifierAttributeSourcesByNature : singularAttributeSourcesByNature );
map
);
}
private static void indexSingularAttributeSource(
String entityName,
String pathBase,
AttributeSourceKey attributeSourceKey,
SingularAttributeSource attributeSource,
Map<SingularAttributeSource.Nature, Map<AttributeSourceKey, SingularAttributeSource>> map) {
final Map<AttributeSourceKey, SingularAttributeSource> singularAttributeSources;
@ -303,10 +316,9 @@ public class SourceIndex {
singularAttributeSources = new LinkedHashMap<AttributeSourceKey,SingularAttributeSource>();
map.put( attributeSource.getNature(), singularAttributeSources );
}
AttributeSourceKey key = new AttributeSourceKey( entityName, pathBase, attributeSource.getName() );
if ( singularAttributeSources.put( key, attributeSource ) != null ) {
if ( singularAttributeSources.put( attributeSourceKey, attributeSource ) != null ) {
throw new AssertionFailure(
String.format( "Attempt to reindex attribute source for: [%s]", key )
String.format( "Attempt to reindex attribute source for: [%s]", attributeSourceKey )
);
}
}
@ -351,7 +363,7 @@ public class SourceIndex {
return Collections.unmodifiableMap( map );
}
private void resolveAssociationSources() {
private void resolveAssociationSources(final EntityBinding entityBinding) {
for ( Map.Entry<AttributeSourceKey,PluralAttributeSource> entry : inversePluralAttributeSourcesByKey.entrySet() ) {
final AttributeSourceKey pluralAttributeSourceKey = entry.getKey();
final PluralAttributeSource pluralAttributeSource = entry.getValue();
@ -372,6 +384,44 @@ public class SourceIndex {
);
}
}
final Map<AttributeSourceKey,SingularAttributeSource> unresolvedSingularAttributeSourceMap =
singularAttributeSourcesByNature.get( null );
if ( unresolvedSingularAttributeSourceMap != null ) {
for ( Iterator<Map.Entry<AttributeSourceKey,SingularAttributeSource>> it = unresolvedSingularAttributeSourceMap.entrySet().iterator(); it.hasNext(); ) {
final Map.Entry<AttributeSourceKey,SingularAttributeSource> entry = it.next();
final AttributeSourceKey attributeSourceKey = entry.getKey();
final SingularAttributeSource attributeSource = entry.getValue();
if ( !ToOneAttributeSource.class.isInstance( attributeSource ) ) {
throw new AssertionFailure(
String.format( "Only a ToOneAttributeSource is expected to have a null nature; attribute: %s ", attributeSourceKey )
);
}
ToOneAttributeSource toOneAttributeSource = (ToOneAttributeSource) attributeSource;
toOneAttributeSource.resolveToOneAttributeSourceNature(
new ToOneAttributeSourceNatureResolver.ToOneAttributeSourceNatureResolutionContext() {
@Override
public boolean areIdentifierColumnsDefined() {
return false;
}
@Override
public List<Column> getIdentifierColumns() {
// TODO: should this return columns from EntityIdentifier???
// (broken for joined-subclass)
return entityBinding.getPrimaryTable().getPrimaryKey().getColumns();
}
}
);
if ( toOneAttributeSource.getNature() == null ) {
throw new AssertionFailure(
String.format( "Null nature should have been resolved: %s ", attributeSourceKey )
);
}
it.remove();
indexSingularAttributeSource( attributeSourceKey,attributeSource, singularAttributeSourcesByNature );
}
}
}
}
}

View File

@ -37,6 +37,8 @@ import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.id.EntityIdentifierNature;
import org.hibernate.metamodel.internal.source.annotations.attribute.AttributeOverride;
import org.hibernate.metamodel.internal.source.annotations.attribute.BasicAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.MappedAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.SingularAssociationAttribute;
import org.hibernate.metamodel.internal.source.annotations.entity.EmbeddableClass;
import org.hibernate.metamodel.internal.source.annotations.entity.EntityClass;
import org.hibernate.metamodel.internal.source.annotations.entity.IdType;
@ -72,9 +74,9 @@ public class RootEntitySourceImpl extends EntitySourceImpl implements RootEntity
IdType idType = rootEntityClass.getIdType();
switch ( idType ) {
case SIMPLE: {
BasicAttribute attribute = getEntityClass().getIdAttributes().iterator().next();
MappedAttribute attribute = getEntityClass().getIdAttributes().iterator().next();
return new SimpleIdentifierSourceImpl(
attribute,
(BasicAttribute) attribute,
getEntityClass().getAttributeOverrideMap().get(attribute.getName())
);
}
@ -162,7 +164,7 @@ public class RootEntitySourceImpl extends EntitySourceImpl implements RootEntity
public AggregatedCompositeIdentifierSourceImpl(RootEntitySourceImpl rootEntitySource) {
// the entity class reference should contain one single id attribute...
Iterator<BasicAttribute> idAttributes = rootEntitySource.getEntityClass().getIdAttributes().iterator();
Iterator<MappedAttribute> idAttributes = rootEntitySource.getEntityClass().getIdAttributes().iterator();
if ( !idAttributes.hasNext() ) {
throw rootEntitySource.getLocalBindingContext().makeMappingException(
String.format(
@ -171,7 +173,7 @@ public class RootEntitySourceImpl extends EntitySourceImpl implements RootEntity
)
);
}
final BasicAttribute idAttribute = idAttributes.next();
final MappedAttribute idAttribute = idAttributes.next();
if ( idAttributes.hasNext() ) {
throw rootEntitySource.getLocalBindingContext().makeMappingException(
String.format(
@ -261,8 +263,12 @@ public class RootEntitySourceImpl extends EntitySourceImpl implements RootEntity
@Override
public List<SingularAttributeSource> getAttributeSourcesMakingUpIdentifier() {
List<SingularAttributeSource> attributeSources = new ArrayList<SingularAttributeSource>();
for ( BasicAttribute attr : rootEntitySource.getEntityClass().getIdAttributes() ) {
attributeSources.add( new SingularAttributeSourceImpl( attr ) );
for ( MappedAttribute attr : rootEntitySource.getEntityClass().getIdAttributes() ) {
SingularAttributeSource attributeSource =
attr instanceof SingularAssociationAttribute ?
new ToOneAttributeSourceImpl( (SingularAssociationAttribute) attr ) :
new SingularAttributeSourceImpl( attr );
attributeSources.add( attributeSource );
}
return attributeSources;
}

View File

@ -25,6 +25,7 @@ package org.hibernate.metamodel.internal.source.annotations;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -50,6 +51,7 @@ import org.hibernate.metamodel.spi.source.ForeignKeyContributingSource;
import org.hibernate.metamodel.spi.source.RelationalValueSource;
import org.hibernate.metamodel.spi.source.SingularAttributeSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSourceNatureResolver;
import org.hibernate.type.ForeignKeyDirection;
/**
@ -59,7 +61,6 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
private final AssociationAttribute associationAttribute;
private final Set<CascadeStyle> cascadeStyles;
private SingularAttributeSource.Nature nature;
private SingularAttributeSource ownerAttributeSource;
public ToOneAttributeSourceImpl(SingularAssociationAttribute associationAttribute) {
@ -70,25 +71,35 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
associationAttribute.getHibernateCascadeTypes(),
associationAttribute.getContext()
);
this.nature = getNature( associationAttribute );
this.nature = determineNatureIfPossible( associationAttribute );
}
private static Nature getNature(SingularAssociationAttribute associationAttribute) {
private static Nature determineNatureIfPossible(SingularAssociationAttribute associationAttribute) {
if ( MappedAttribute.Nature.MANY_TO_ONE.equals( associationAttribute.getNature() ) ) {
return Nature.MANY_TO_ONE;
}
else if ( MappedAttribute.Nature.ONE_TO_ONE.equals( associationAttribute.getNature() ) ) {
if ( associationAttribute.getMappedBy() != null || associationAttribute.hasPrimaryKeyJoinColumn()) {
if ( associationAttribute.getMappedBy() != null ) {
// This means it is a one-to-one, but it is not working yet.
//return Nature.ONE_TO_ONE;
throw new NotYetImplementedException( "@OneToOne with mappedBy specified is not supported yet." );
}
else if ( associationAttribute.hasPrimaryKeyJoinColumn() ) {
return Nature.ONE_TO_ONE;
}
else if ( associationAttribute.getJoinTableAnnotation() != null ) {
return Nature.MANY_TO_ONE;
}
else if ( associationAttribute.isId() ) {
// if this association is part of the ID then this can't be a one-to-one
return Nature.MANY_TO_ONE;
}
else if ( associationAttribute.getJoinColumnValues() == null ||
associationAttribute.getJoinColumnValues().isEmpty() ) {
return Nature.MANY_TO_ONE;
}
else {
//if ( associationAttribute.getJoinColumnValues() ) {
throw new NotYetImplementedException( "One-to-one without mappedBy configured using annotations is not supported yet." );
// if ID is not initialized, then this can't be a one-to-one (mapToPk == false)
// if join columns are the entity's ID, then it is a one-to-one (mapToPk == true)
return null;
}
}
else {
@ -97,24 +108,29 @@ public class ToOneAttributeSourceImpl extends SingularAttributeSourceImpl implem
}
}
/*
private static Nature determineNature(
ToOneAttributeSource currentAttributeSource
ToOneAttributeSource ownerAttributeSource,
AssociationAttribute associationAttribute) {
switch ( associationAttribute.getNature() ) {
case ONE_TO_ONE:
throw new NotYetImplementedException( );
case MANY_TO_ONE:
return new ManyToAnyPluralAttributeElementSourceImpl( associationAttribute );
// case ONE_TO_MANY:
// return usesJoinTable( ownerAttributeSource ) ?
// new ManyToManyPluralAttributeElementSourceImpl( ownerAttributeSource, associationAttribute, true ) :
// new OneToManyPluralAttributeElementSourceImpl( ownerAttributeSource, associationAttribute );
public Nature resolveToOneAttributeSourceNature(ToOneAttributeSourceNatureResolver.ToOneAttributeSourceNatureResolutionContext context) {
if ( nature != null ) { return nature; }
final List<org.hibernate.metamodel.spi.relational.Column> idColumns = context.getIdentifierColumns();
if ( associationAttribute.getJoinColumnValues().size() != idColumns.size() ) {
nature = Nature.MANY_TO_ONE;
}
throw new AssertionError( "Unexpected attribute nature for a to-one association attribute:" + associationAttribute.getNature() );
else {
Set<String> joinColumnNames = new HashSet<String>( associationAttribute.getJoinColumnValues().size() );
for ( Column joinColumn : associationAttribute.getJoinColumnValues() ) {
joinColumnNames.add( joinColumn.getName() );
}
// if join columns are the entity's ID, then it is a one-to-one (mapToPk == true)
boolean areJoinColumnsSameAsIdColumns = true;
for ( org.hibernate.metamodel.spi.relational.Column idColumn : idColumns ) {
if ( ! joinColumnNames.contains( idColumn.getColumnName().getText() ) ) {
areJoinColumnsSameAsIdColumns = false;
break;
}
}
nature = areJoinColumnsSameAsIdColumns ? Nature.ONE_TO_ONE : Nature.MANY_TO_ONE;
}
return nature;
}
*/
@Override
public Nature getNature() {

View File

@ -106,7 +106,7 @@ public class ConfiguredClass {
/**
* The id attributes
*/
private final Map<String, BasicAttribute> idAttributeMap;
private final Map<String, MappedAttribute> idAttributeMap;
/**
* The mapped association attributes for this entity
@ -164,7 +164,7 @@ public class ConfiguredClass {
this.customTuplizer = determineCustomTuplizer();
this.simpleAttributeMap = new TreeMap<String, BasicAttribute>();
this.idAttributeMap = new TreeMap<String, BasicAttribute>();
this.idAttributeMap = new TreeMap<String, MappedAttribute>();
this.associationAttributeMap = new TreeMap<String, AssociationAttribute>();
this.localBindingContext = new EntityBindingContext( context, this );
@ -210,7 +210,7 @@ public class ConfiguredClass {
return idAttributeMap.containsKey( attributeName );
}
public Collection<BasicAttribute> getIdAttributes() {
public Collection<MappedAttribute> getIdAttributes() {
return idAttributeMap.values();
}
@ -520,7 +520,12 @@ public class ConfiguredClass {
annotations,
getLocalBindingContext()
);
associationAttributeMap.put( attributeName, attribute );
if ( attribute.isId() ) {
idAttributeMap.put( attributeName, attribute );
}
else {
associationAttributeMap.put( attributeName, attribute );
}
break;
}
case ELEMENT_COLLECTION_EMBEDDABLE:

View File

@ -42,6 +42,7 @@ import org.hibernate.metamodel.internal.source.annotations.AnnotationBindingCont
import org.hibernate.metamodel.internal.source.annotations.attribute.BasicAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.Column;
import org.hibernate.metamodel.internal.source.annotations.attribute.FormulaValue;
import org.hibernate.metamodel.internal.source.annotations.attribute.MappedAttribute;
import org.hibernate.metamodel.internal.source.annotations.attribute.PrimaryKeyJoinColumn;
import org.hibernate.metamodel.internal.source.annotations.util.HibernateDotNames;
import org.hibernate.metamodel.internal.source.annotations.util.JPADotNames;
@ -163,8 +164,8 @@ public class RootEntityClass extends EntityClass {
return attributes;
}
public Collection<BasicAttribute> getIdAttributes() {
List<BasicAttribute> attributes = new ArrayList<BasicAttribute>();
public Collection<MappedAttribute> getIdAttributes() {
List<MappedAttribute> attributes = new ArrayList<MappedAttribute>();
// get all id attributes defined on this entity
attributes.addAll( super.getIdAttributes() );

View File

@ -35,6 +35,7 @@ import org.hibernate.metamodel.spi.binding.SingularAttributeBinding;
import org.hibernate.metamodel.spi.source.MetaAttributeSource;
import org.hibernate.metamodel.spi.source.RelationalValueSource;
import org.hibernate.metamodel.spi.source.SingularAttributeSource;
import org.hibernate.metamodel.spi.source.ToOneAttributeSourceNatureResolver;
import org.hibernate.type.ForeignKeyDirection;
/**
@ -115,6 +116,11 @@ class KeyManyToOneSourceImpl
return Nature.MANY_TO_ONE;
}
@Override
public Nature resolveToOneAttributeSourceNature(ToOneAttributeSourceNatureResolutionContext context) {
return getNature();
}
@Override
public boolean isVirtualAttribute() {
return false;

View File

@ -148,6 +148,11 @@ class ManyToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl {
return Nature.MANY_TO_ONE;
}
@Override
public Nature resolveToOneAttributeSourceNature(ToOneAttributeSourceNatureResolutionContext context) {
return getNature();
}
@Override
public boolean areValuesIncludedInInsertByDefault() {
return manyToOneElement.isInsert();

View File

@ -140,6 +140,11 @@ class OneToOneAttributeSourceImpl extends AbstractToOneAttributeSourceImpl {
return Nature.ONE_TO_ONE;
}
@Override
public Nature resolveToOneAttributeSourceNature(ToOneAttributeSourceNatureResolutionContext context) {
return getNature();
}
@Override
public boolean isVirtualAttribute() {
return false;

View File

@ -25,6 +25,8 @@ package org.hibernate.metamodel.spi.binding;
import java.util.List;
import org.hibernate.metamodel.spi.relational.Column;
/**
* Basic contract describing the commonality between the various types of collection element mappings.
*

View File

@ -26,6 +26,7 @@ package org.hibernate.metamodel.spi.binding;
import java.util.List;
import org.hibernate.metamodel.spi.domain.SingularAttribute;
import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.source.MetaAttributeContext;
/**
@ -68,6 +69,25 @@ public abstract class AbstractSingularAttributeBinding
return !getRelationalValueBindingContainer().hasNonNullableRelationalValueBinding();
}
@Override
public boolean isOptional() {
final EntityBinding entityBinding = getContainer().seekEntityBinding();
final TableSpecification entityPrimaryTable = entityBinding.getPrimaryTable();
for (RelationalValueBinding relationalValueBinding : getRelationalValueBindings() ) {
final TableSpecification table = relationalValueBinding.getTable();
if ( table.equals( entityPrimaryTable ) ) {
// primary table is not optional.
return false;
}
final SecondaryTable secondaryTable = entityBinding.getSecondaryTables().get( table.getLogicalName() );
// a secondaryTable can be null if it is a non-joined, collection/association table
if ( secondaryTable == null || ! secondaryTable.isOptional() ) {
return false;
}
}
return true;
}
@Override
public boolean isIncludedInInsert() {
return getRelationalValueBindingContainer().hasInsertableRelationalValueBinding();

View File

@ -195,7 +195,8 @@ public class EntityIdentifier {
}
protected boolean isBound() {
return entityIdentifierBinding != null; }
return entityIdentifierBinding != null;
}
public int getColumnCount() {
ensureBound();

View File

@ -25,6 +25,8 @@ package org.hibernate.metamodel.spi.binding;
import java.util.List;
import org.hibernate.metamodel.spi.relational.Column;
/**
* Common information pertaining to the binding of the various plural attribute natures (one-to-many, basic, etc).
*

View File

@ -54,6 +54,14 @@ public interface SingularAttributeBinding extends AttributeBinding {
*/
public boolean isNullable();
/**
* Convenience method to determine if all tables (primary and secondary) involved with this attribute
* binding are optional.
*
* @return true, if all tables involved with this attribute are optional; false, otherwise.
*/
public boolean isOptional();
/**
* Convenience method to determine if any {@link RelationalValueBinding simple value bindings} are inserted.
*

View File

@ -35,7 +35,7 @@ import org.hibernate.type.ForeignKeyDirection;
* @author Steve Ebersole
*/
public interface ToOneAttributeSource
extends SingularAttributeSource, ForeignKeyContributingSource, FetchableAttributeSource, CascadeStyleSource {
extends SingularAttributeSource, ToOneAttributeSourceNatureResolver, ForeignKeyContributingSource, FetchableAttributeSource, CascadeStyleSource {
/**
* Obtain the name of the referenced entity.

View File

@ -0,0 +1,42 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.spi.source;
import java.util.List;
import org.hibernate.metamodel.spi.binding.EntityIdentifier;
import org.hibernate.metamodel.spi.relational.Column;
/**
* @author Gail Badner
*/
public interface ToOneAttributeSourceNatureResolver {
SingularAttributeSource.Nature resolveToOneAttributeSourceNature(ToOneAttributeSourceNatureResolutionContext context);
public static interface ToOneAttributeSourceNatureResolutionContext {
boolean areIdentifierColumnsDefined();
List<org.hibernate.metamodel.spi.relational.Column> getIdentifierColumns();
}
}

View File

@ -29,6 +29,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@ -1057,21 +1058,24 @@ public abstract class AbstractEntityPersister
classes.add( ( (EntityBinding) attributeBinding.getContainer() ).getEntity().getName() );
boolean isDefinedBySubclass = ! thisClassProperties.contains( attributeBinding );
definedBySubclass.add( isDefinedBySubclass );
// TODOFix this when join tables are supported...
//propNullables.add( attributeBinding.isOptional() || isDefinedBySubclass );
propNullables.add(
! attributeBinding.getAttribute().isSingular() ||
( (SingularAttributeBinding) attributeBinding).isNullable() ||
isDefinedBySubclass
);
final boolean propIsNullable;
final List<RelationalValueBinding> relationalValueBindings;
if ( attributeBinding.getAttribute().isSingular() ) {
final SingularAttributeBinding singularAttributeBinding = (SingularAttributeBinding) attributeBinding;
propIsNullable =
singularAttributeBinding.isOptional() ||
singularAttributeBinding.isNullable() ||
isDefinedBySubclass;
relationalValueBindings = singularAttributeBinding.getRelationalValueBindings();
}
else {
// plural attributes are considered nullable
propIsNullable = true;
relationalValueBindings = Collections.emptyList();
}
propNullables.add( propIsNullable );
types.add( attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping() );
List<RelationalValueBinding> relationalValueBindings =
attributeBinding.getAttribute().isSingular() ?
( (SingularAttributeBinding) attributeBinding ).getRelationalValueBindings() :
null;
final int span = relationalValueBindings == null ? 0 : relationalValueBindings.size();
final int span = relationalValueBindings.size();
String[] cols = new String[ span ];
String[] readers = new String[ span ];
String[] readerTemplates = new String[ span ];
@ -1081,45 +1085,43 @@ public abstract class AbstractEntityPersister
int l = 0;
Boolean lazy = attributeBinding.isLazy() && lazyAvailable;
if ( relationalValueBindings != null ) {
for ( RelationalValueBinding valueBinding : relationalValueBindings ) {
if ( valueBinding.isDerived() ) {
DerivedValue derivedValue = DerivedValue.class.cast( valueBinding.getValue() );
String template = getTemplateFromString( derivedValue.getExpression(), factory );
formnos[l] = formulaTemplates.size();
colnos[l] = -1;
formulaTemplates.add( template );
forms[l] = template;
formulas.add( derivedValue.getExpression() );
formulaAliases.add( derivedValue.getAlias( factory.getDialect(), null ) );
formulasLazy.add( lazy );
}
else {
org.hibernate.metamodel.spi.relational.Column col = org.hibernate.metamodel.spi.relational.Column.class.cast( valueBinding.getValue() );
String colName = col.getColumnName().getText( factory.getDialect() );
colnos[l] = columns.size(); //before add :-)
formnos[l] = -1;
columns.add( colName );
cols[l] = colName;
aliases.add(
col.getAlias(
factory.getDialect(),
valueBinding.getTable()
)
);
columnsLazy.add( lazy );
columnSelectables.add( ! attributeBinding.isBackRef() );
readers[l] =
col.getReadFragment() == null ?
col.getColumnName().getText( factory.getDialect() ) :
col.getReadFragment();
String readerTemplate = getTemplateFromColumn( col, factory );
readerTemplates[l] = readerTemplate;
columnReaderTemplates.add( readerTemplate );
}
l++;
for ( RelationalValueBinding valueBinding : relationalValueBindings ) {
if ( valueBinding.isDerived() ) {
DerivedValue derivedValue = DerivedValue.class.cast( valueBinding.getValue() );
String template = getTemplateFromString( derivedValue.getExpression(), factory );
formnos[l] = formulaTemplates.size();
colnos[l] = -1;
formulaTemplates.add( template );
forms[l] = template;
formulas.add( derivedValue.getExpression() );
formulaAliases.add( derivedValue.getAlias( factory.getDialect(), null ) );
formulasLazy.add( lazy );
}
else {
org.hibernate.metamodel.spi.relational.Column col = org.hibernate.metamodel.spi.relational.Column.class.cast( valueBinding.getValue() );
String colName = col.getColumnName().getText( factory.getDialect() );
colnos[l] = columns.size(); //before add :-)
formnos[l] = -1;
columns.add( colName );
cols[l] = colName;
aliases.add(
col.getAlias(
factory.getDialect(),
valueBinding.getTable()
)
);
columnsLazy.add( lazy );
columnSelectables.add( ! attributeBinding.isBackRef() );
readers[l] =
col.getReadFragment() == null ?
col.getColumnName().getText( factory.getDialect() ) :
col.getReadFragment();
String readerTemplate = getTemplateFromColumn( col, factory );
readerTemplates[l] = readerTemplate;
columnReaderTemplates.add( readerTemplate );
}
l++;
}
propColumns.add( cols );
propColumnReaders.add( readers );
@ -1308,7 +1310,9 @@ public abstract class AbstractEntityPersister
final Serializable id,
final EntityEntry entry) {
if ( !hasLazyProperties() ) throw new AssertionFailure( "no lazy properties" );
if ( !hasLazyProperties() ) {
throw new AssertionFailure( "no lazy properties" );
}
LOG.trace( "Initializing lazy properties from datastore" );

View File

@ -89,7 +89,7 @@ public class PojoInstantiator implements Instantiator, Serializable {
public PojoInstantiator(EntityBinding entityBinding, ReflectionOptimizer.InstantiationOptimizer optimizer) {
this.mappedClass = entityBinding.getEntity().getClassReference();
this.isAbstract = ReflectHelper.isAbstractClass( mappedClass );
this.proxyInterface = entityBinding.getProxyInterfaceType().getValue();
this.proxyInterface = entityBinding.getProxyInterfaceType() == null ? null : entityBinding.getProxyInterfaceType().getValue();
this.embeddedIdentifier = entityBinding.getHierarchyDetails().getEntityIdentifier().isNonAggregatedComposite();
this.optimizer = optimizer;

View File

@ -243,7 +243,7 @@ public class PropertyFactory {
property.getGeneration() == PropertyGeneration.INSERT
|| property.getGeneration() == PropertyGeneration.ALWAYS,
property.getGeneration() == PropertyGeneration.ALWAYS,
property.isNullable(),
property.isNullable() || property.isOptional(),
!lazy,
property.isIncludedInOptimisticLocking(),
cascadeStyle,
@ -333,7 +333,7 @@ public class PropertyFactory {
propertyGeneration == PropertyGeneration.INSERT
|| propertyGeneration == PropertyGeneration.ALWAYS,
propertyGeneration == PropertyGeneration.ALWAYS,
singularAttributeBinding.isNullable(),
singularAttributeBinding.isNullable() || singularAttributeBinding.isOptional(),
alwaysDirtyCheck || singularAttributeBinding.isIncludedInUpdate(),
singularAttributeBinding.isIncludedInOptimisticLocking(),
cascadeStyle,

View File

@ -385,7 +385,7 @@ public class EntityMetamodel implements Serializable {
Class<?> mappedClass = null;
if ( hasPojoRepresentation ) {
mappedClass = entityBinding.getEntity().getClassReference();
proxyInterfaceClass = entityBinding.getProxyInterfaceType().getValue();
proxyInterfaceClass = entityBinding.getProxyInterfaceType() == null ? null : entityBinding.getProxyInterfaceType().getValue();
instrumentationMetadata = Environment.getBytecodeProvider().getEntityInstrumentationMetadata( mappedClass );
}
else {

View File

@ -116,7 +116,7 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer {
public PojoEntityTuplizer(EntityMetamodel entityMetamodel, EntityBinding mappedEntity) {
super( entityMetamodel, mappedEntity );
this.mappedClass = mappedEntity.getEntity().getClassReference();
this.proxyInterface = mappedEntity.getProxyInterfaceType().getValue();
this.proxyInterface = mappedEntity.getProxyInterfaceType() == null ? null : mappedEntity.getProxyInterfaceType().getValue();
//with Jandex, if this entity is mapped by annotation, then we already get this info from jandex.
//but i don't know if this mirror improvement worth it.
this.lifecycleImplementor = Lifecycle.class.isAssignableFrom( mappedClass );

View File

@ -40,7 +40,6 @@ import static org.junit.Assert.fail;
* @author Gail Badner
*/
@SuppressWarnings("unchecked")
@FailureExpectedWithNewMetamodel
public class NonNullableCircularDependencyCascadeTest extends BaseCoreFunctionalTestCase {
@Test
public void testIdClassInSuperclass() throws Exception {

View File

@ -33,7 +33,6 @@ import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
@RequiresDialectFeature(DialectChecks.SupportsIdentityColumns.class)
@FailureExpectedWithNewMetamodel
public class CascadeCircleIdentityIdTest extends BaseCoreFunctionalTestCase {
@Test
@TestForIssue( jiraKey = "HHH-5472" )

View File

@ -33,7 +33,6 @@ import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
@RequiresDialectFeature(DialectChecks.SupportsSequences.class)
@FailureExpectedWithNewMetamodel
public class CascadeCircleSequenceIdTest extends BaseCoreFunctionalTestCase {
@Test
@TestForIssue( jiraKey = "HHH-5472" )

View File

@ -31,7 +31,6 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
@FailureExpectedWithNewMetamodel
public class CompositeDerivedIdentityTest extends BaseCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {

View File

@ -41,9 +41,9 @@ import static org.junit.Assert.assertTrue;
* @author Emmanuel Bernard
*/
@FailureExpectedWithNewMetamodel
public class DerivedIdentitySimpleParentIdClassDepTest extends BaseCoreFunctionalTestCase {
@Test
@FailureExpectedWithNewMetamodel
public void testManyToOne() throws Exception {
assertTrue( SchemaUtil.isColumnPresent( "Dependent", "emp_empId", metadata() ) );
assertTrue( ! SchemaUtil.isColumnPresent( "Dependent", "emp", metadata() ) );

View File

@ -27,6 +27,7 @@ import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.test.util.SchemaUtil;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
@ -36,6 +37,7 @@ import static org.junit.Assert.assertTrue;
/**
* @author Emmanuel Bernard
*/
@FailureExpectedWithNewMetamodel
public class DerivedIdentityEmbeddedIdParentIdClassTest extends BaseCoreFunctionalTestCase {
@Test
public void testManyToOne() throws Exception {

View File

@ -55,7 +55,7 @@ import static org.junit.Assert.fail;
/**
* @author Emmanuel Bernard
*/
@FailureExpectedWithNewMetamodel
@FailureExpectedWithNewMetamodel( message = "@OneToOne with mappedBy specified is not supported yet" )
public class BasicHibernateAnnotationsTest extends BaseCoreFunctionalTestCase {
@Override
protected boolean isCleanupTestDataRequired() {
@ -101,6 +101,7 @@ public class BasicHibernateAnnotationsTest extends BaseCoreFunctionalTestCase {
@Test
@RequiresDialectFeature( DialectChecks.SupportsExpectedLobUsagePattern.class )
@FailureExpectedWithNewMetamodel
public void testVersioning() throws Exception {
Forest forest = new Forest();
forest.setName( "Fontainebleau" );
@ -327,6 +328,7 @@ public class BasicHibernateAnnotationsTest extends BaseCoreFunctionalTestCase {
}
@Test
@FailureExpectedWithNewMetamodel
public void testCascadedDeleteOfChildEntitiesBug2() {
// Relationship is one SoccerTeam to many Players.
// Create a SoccerTeam (parent) and three Players (child).
@ -377,6 +379,7 @@ public class BasicHibernateAnnotationsTest extends BaseCoreFunctionalTestCase {
}
@Test
@FailureExpectedWithNewMetamodel
public void testCascadedDeleteOfChildOneToOne() {
// create two single player teams (for one versus one match of soccer)
// and associate teams with players via the special OneVOne methods.
@ -463,6 +466,7 @@ public class BasicHibernateAnnotationsTest extends BaseCoreFunctionalTestCase {
* defined on a parent MappedSuperclass(s)
*/
@Test
@FailureExpectedWithNewMetamodel
public void testInheritFiltersFromMappedSuperclass() throws Exception {
Session s;
Transaction tx;

View File

@ -4,6 +4,7 @@ import java.io.Serializable;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
@ -16,7 +17,7 @@ import javax.persistence.OneToMany;
@Entity
public class Card {
@Id
@EmbeddedId
private CardPrimaryKey primaryKey = new CardPrimaryKey();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "primaryKey.card")

View File

@ -2,6 +2,7 @@
package org.hibernate.test.annotations.idmanytoone;
import java.io.Serializable;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@ -12,7 +13,7 @@ import javax.persistence.ManyToOne;
@Entity
public class CardField {
@Id
@EmbeddedId
private PrimaryKey primaryKey = new PrimaryKey();
@ManyToOne

View File

@ -15,7 +15,7 @@ import javax.persistence.Table;
@Entity
@Table(name = "Bs")
@Table(name = "`Bs`")
public class Customer implements Serializable {
@Id @GeneratedValue
public Integer id;

View File

@ -38,7 +38,6 @@ import static org.junit.Assert.assertEquals;
/**
* @author Emmanuel Bernard
*/
@FailureExpectedWithNewMetamodel
public class IdManyToOneTest extends BaseCoreFunctionalTestCase {
@Test
public void testFkCreationOrdering() throws Exception {

View File

@ -40,9 +40,8 @@ public class ShoppingBasketsPK implements Serializable {
}
@Id
@ManyToOne(cascade={ CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH })
@ManyToOne(cascade={ CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH }, fetch= FetchType.LAZY )
@JoinColumns({ @JoinColumn(name="customerID", referencedColumnName="customerID") })
@Basic(fetch= FetchType.LAZY)
private Customers owner;
public void setOwner(Customers value) {

View File

@ -2,6 +2,7 @@
package org.hibernate.test.annotations.manytoone;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
@ -34,7 +35,7 @@ public class Node implements Serializable {
return id.hashCode();
}
@Id
@EmbeddedId
public NodePk getId() {
return id;
}

View File

@ -1,6 +1,7 @@
//$Id$
package org.hibernate.test.annotations.manytoone;
import java.io.Serializable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@ -11,7 +12,7 @@ import javax.persistence.Table;
@Entity
@Table(name = "tbl_parent")
public class Parent implements Serializable {
@Id
@EmbeddedId
public ParentPk id;
public int age;

View File

@ -42,7 +42,7 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
/**
* @author Guenther Demetz
*/
@FailureExpectedWithNewMetamodel
@FailureExpectedWithNewMetamodel( message = "@OneToOne with mappedBy specified is not supported yet" )
public class ImmutableNaturalKeyLookupTest extends BaseCoreFunctionalTestCase {
@TestForIssue(jiraKey = "HHH-4838")

View File

@ -51,7 +51,7 @@ import static org.junit.Assert.assertTrue;
/**
* @author Emmanuel Bernard
*/
@FailureExpectedWithNewMetamodel
@FailureExpectedWithNewMetamodel( message = "requires support for @OneToOne with mappedBy" )
public class OneToOneTest extends BaseCoreFunctionalTestCase {
@Test
public void testEagerFetching() throws Exception {

View File

@ -29,6 +29,7 @@ import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.id.IdentifierGenerationException;
import org.hibernate.testing.FailureExpectedWithNewMetamodel;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
@ -40,6 +41,7 @@ import static org.junit.Assert.fail;
* @author Emmanuel Bernard
* @author Gail Badner
*/
@FailureExpectedWithNewMetamodel( message = "requires support for @OneToOne with mappedBy" )
public class OptionalOneToOneMappedByTest extends BaseCoreFunctionalTestCase {
// @OneToOne(mappedBy="address") with foreign generator

View File

@ -42,7 +42,7 @@ import static org.junit.Assert.fail;
* @author Emmanuel Bernard
* @author Gail Badner
*/
@FailureExpectedWithNewMetamodel(message = "Needs one to one mapping support. See Binder#bindSingularAttribute")
@FailureExpectedWithNewMetamodel( message = "requires support for @OneToOne with mappedBy" )
public class OptionalOneToOnePKJCTest extends BaseCoreFunctionalTestCase {
@Test

View File

@ -40,7 +40,7 @@ import static org.junit.Assert.fail;
* @author Emmanuel Bernard
*/
@TestForIssue( jiraKey = "HHH-4851" )
@FailureExpectedWithNewMetamodel
@FailureExpectedWithNewMetamodel( message = "requires support for @OneToOne with mappedBy" )
public class HHH4851Test extends BaseCoreFunctionalTestCase {
@Test
public void testHHH4851() throws Exception {

View File

@ -10,11 +10,9 @@ import org.jboss.logging.Logger;
import org.junit.Assert;
import org.junit.Test;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.mapping.MetadataSource;
import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.service.ServiceRegistry;
@ -30,7 +28,7 @@ import org.hibernate.tool.schema.spi.SchemaManagementTool;
* @author Hardy Ferentschik
*
*/
@FailureExpectedWithNewMetamodel
@FailureExpectedWithNewMetamodel( message = "requires support for @OneToOne with mappedBy" )
public class NullablePrimaryKeyTest extends BaseUnitTestCase {
private static final Logger log = Logger.getLogger( NullablePrimaryKeyTest.class );
@Test

View File

@ -25,8 +25,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Iterator;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@ -77,6 +75,7 @@ public class ConstraintTest extends BaseCoreFunctionalTestCase {
@Test
@TestForIssue( jiraKey = "HHH-1904" )
@FailureExpectedWithNewMetamodel
public void testConstraintNameLength() {
TableSpecification table = SchemaUtil.getTable( DataPoint2.class, metadata() );
@ -140,4 +139,4 @@ public class ConstraintTest extends BaseCoreFunctionalTestCase {
@org.hibernate.annotations.ForeignKey(name = EXPLICIT_FK_NAME)
public DataPoint explicit;
}
}
}

View File

@ -35,7 +35,6 @@ import static org.junit.Assert.assertTrue;
/**
* @author Gavin King
*/
//@FailureExpectedWithNewMetamodel
public class IJ2Test extends LegacyTestCase {
@Override

View File

@ -45,7 +45,6 @@ import static org.junit.Assert.assertTrue;
* @author Emmanuel Bernard
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
//@FailureExpectedWithNewMetamodel
public class NamingStrategyTest extends BaseCoreFunctionalTestCase {
@Override
public void configure(Configuration cfg) {

View File

@ -34,7 +34,6 @@ import static org.junit.Assert.assertNull;
/**
* @author Steve Ebersole
*/
//@FailureExpectedWithNewMetamodel
public class NullableNaturalIdTest extends BaseCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {

View File

@ -42,7 +42,6 @@ import static org.junit.Assert.assertNull;
/**
* @author Gavin King
*/
@FailureExpectedWithNewMetamodel
public class JoinedSubclassOneToOneTest extends BaseCoreFunctionalTestCase {
@Override
public String[] getMappings() {

View File

@ -42,7 +42,6 @@ import static org.junit.Assert.assertTrue;
/**
* @author Gavin King
*/
@FailureExpectedWithNewMetamodel( message = "Joined attributes are not supported yet" )
public class OneToOneLinkTest extends BaseCoreFunctionalTestCase {
@Override
public String[] getMappings() {