HHH-11255 - NaturalId mapping fails when using a composite natural identifier

Add support for adding unique constraints to composite entity properties, like when using a @NaturalId with an @Embedded property
This commit is contained in:
Vlad Mihalcea 2016-11-17 15:27:27 +02:00
parent 95b1e27902
commit 74a789e617
4 changed files with 107 additions and 7 deletions

View File

@ -6,13 +6,20 @@
*/
package org.hibernate.cfg;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.hibernate.AnnotationException;
import org.hibernate.MappingException;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.Index;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.UniqueKey;
/**
* @author Emmanuel Bernard
@ -64,10 +71,27 @@ public class IndexOrUniqueKeySecondPass implements SecondPass {
}
if ( column != null ) {
this.table = column.getTable();
addConstraintToColumn(
buildingContext.getMetadataCollector()
PersistentClass persistentClass = (PersistentClass) persistentClasses.get( column.getPropertyHolder().getEntityName() );
Property property = persistentClass.getProperty( column.getPropertyName() );
if ( property.getValue() instanceof Component ) {
Component component = (Component) property.getValue();
List<Column> columns = new ArrayList<>();
component.getColumnIterator().forEachRemaining( selectable -> {
if ( selectable instanceof Column ) {
columns.add( (Column) selectable );
}
} );
addConstraintToColumns( columns );
}
else {
addConstraintToColumn(
buildingContext.getMetadataCollector()
.getLogicalColumnName( table, column.getMappingColumn().getQuotedName() )
);
);
}
}
}
@ -89,4 +113,19 @@ public class IndexOrUniqueKeySecondPass implements SecondPass {
table.getOrCreateIndex( indexName ).addColumn( column );
}
}
private void addConstraintToColumns(List<Column> columns) {
if ( unique ) {
UniqueKey uniqueKey = table.getOrCreateUniqueKey( indexName );
for ( Column column : columns ) {
uniqueKey.addColumn( column );
}
}
else {
Index index = table.getOrCreateIndex( indexName );
for ( Column column : columns ) {
index.addColumn( column );
}
}
}
}

View File

@ -12,25 +12,27 @@ import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.junit.Test;
/**
* @author Steve Ebersole
*/
@TestForIssue(jiraKey = "HHH-11255")
public class CompositeNaturalIdMappingTest extends BaseUnitTestCase {
@Test
@FailureExpected( jiraKey = "tbd" )
public void test() {
final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build();
final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder()
.build();
try {
Metadata meta = new MetadataSources( ssr )
.addAnnotatedClass( PostalCarrier.class )
.addAnnotatedClass( PostalCode.class )
.buildMetadata();
( ( MetadataImplementor) meta ).validate();
( (MetadataImplementor) meta ).validate();
}
finally {
StandardServiceRegistryBuilder.destroy( ssr );

View File

@ -0,0 +1,56 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.naturalid.composite;
import org.hibernate.Session;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
/**
* @author Vlad Mihalcea
*/
@TestForIssue(jiraKey = "HHH-11255")
public class EmbeddedNaturalIdTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
PostalCarrier.class
};
}
@Test
public void test() {
doInJPA( this::entityManagerFactory, entityManager -> {
PostalCarrier postalCarrier = new PostalCarrier();
postalCarrier.setId( 1L );
postalCarrier.setPostalCode( new PostalCode() );
postalCarrier.getPostalCode().setCode( "ABC123" );
postalCarrier.getPostalCode().setCountry( "US" );
entityManager.persist( postalCarrier );
} );
doInJPA( this::entityManagerFactory, entityManager -> {
PostalCarrier postalCarrier = entityManager.unwrap( Session.class )
.byNaturalId( PostalCarrier.class )
.using( "postalCode", new PostalCode( "ABC123", "US" ) )
.load();
assertEquals( Long.valueOf( 1L ), postalCarrier.getId() );
} );
doInJPA( this::entityManagerFactory, entityManager -> {
PostalCarrier postalCarrier = entityManager.unwrap( Session.class )
.bySimpleNaturalId( PostalCarrier.class )
.load( new PostalCode( "ABC123", "US" ) );
assertEquals( Long.valueOf( 1L ), postalCarrier.getId() );
} );
}
}

View File

@ -24,6 +24,9 @@ public class PostalCarrier {
@Embedded
private PostalCode postalCode;
public PostalCarrier() {
}
public PostalCarrier(long id, PostalCode postalCode) {
this.id = id;
this.postalCode = postalCode;