From 4477baf53bb8592800115e0ce1d1c4cd48434338 Mon Sep 17 00:00:00 2001 From: echunca Date: Fri, 21 Jul 2017 17:26:24 +0800 Subject: [PATCH] HHH-11826: ImplicitNamingStrategyComponentPathImpl generates invalid SQL for Entity with Embedded ElementCollection --- .../org/hibernate/cfg/Ejb3JoinColumn.java | 6 + ...ponentNamingStrategyForJoinColumnTest.java | 212 ++++++++++++++++++ 2 files changed, 218 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/namingstrategy/components/ComponentNamingStrategyForJoinColumnTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java index ce63785283..5e17992064 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java @@ -704,6 +704,12 @@ public class Ejb3JoinColumn extends Ejb3Column { } ); + // HHH-11826 magic. See Ejb3Column and the HHH-6005 comments + if ( columnIdentifier.getText().contains( "_collection&&element_" ) ) { + columnIdentifier = Identifier.toIdentifier( columnIdentifier.getText().replace( "_collection&&element_", "_" ), + columnIdentifier.isQuoted() ); + } + //one element was quoted so we quote if ( isRefColumnQuoted || StringHelper.isQuoted( logicalTableName ) ) { columnIdentifier = Identifier.quote( columnIdentifier ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/namingstrategy/components/ComponentNamingStrategyForJoinColumnTest.java b/hibernate-core/src/test/java/org/hibernate/test/namingstrategy/components/ComponentNamingStrategyForJoinColumnTest.java new file mode 100644 index 0000000000..46a2abe9f9 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/namingstrategy/components/ComponentNamingStrategyForJoinColumnTest.java @@ -0,0 +1,212 @@ +/* + * 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 . + */ +package org.hibernate.test.namingstrategy.components; + +import java.util.ArrayList; +import java.util.List; +import javax.persistence.Basic; +import javax.persistence.ElementCollection; +import javax.persistence.Embeddable; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @author Cai Chun + */ +@TestForIssue(jiraKey = "HHH-11826") +public class ComponentNamingStrategyForJoinColumnTest extends BaseUnitTestCase { + + @Test + public void testNamingComponentPath() { + final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); + + try { + final MetadataSources ms = new MetadataSources( ssr ) + .addAnnotatedClass( Employee.class ) + .addAnnotatedClass( BankAccounts.class ) + .addAnnotatedClass( BankAccount.class ) + .addAnnotatedClass( WebUser.class ); + + final Metadata metadata = ms.getMetadataBuilder() + .applyImplicitNamingStrategy( + ImplicitNamingStrategyComponentPathImpl.INSTANCE ) + .build(); + + checkDefaultJoinTableAndAllColumnNames( + metadata, + Employee.class, + "bankAccounts.accounts", + "ComponentNamingStrategyForJoinColumnTest$Employee_bankAccounts_accounts", + "ComponentNamingStrategyForJoinColumnTest$Employee_id", + new String[] { + "ComponentNamingStrategyForJoinColumnTest$Employee_id", + "bankAccounts_accounts_accountNumber", + "bankAccounts_accounts_bankName", + "bankAccounts_accounts_verificationUser_id" + } + ); + } + finally { + StandardServiceRegistryBuilder.destroy( ssr ); + } + } + + protected void checkDefaultJoinTableAndAllColumnNames( + Metadata metadata, + Class ownerEntityClass, + String ownerCollectionPropertyName, + String expectedCollectionTableName, + String ownerForeignKeyNameExpected, + String[] columnNames) { + final org.hibernate.mapping.Collection collection = metadata.getCollectionBinding( ownerEntityClass.getName() + '.' + ownerCollectionPropertyName ); + + final org.hibernate.mapping.Table table = collection.getCollectionTable(); + assertEquals( expectedCollectionTableName, table.getName() ); + + // The default owner and inverse join columns can only be computed if they have PK with 1 column. + assertEquals( 1, collection.getOwner().getKey().getColumnSpan() ); + assertEquals( + ownerForeignKeyNameExpected, + collection.getKey().getColumnIterator().next().getText() + ); + + int columnNumber = table.getColumnSpan(); + for ( int i = 0; i < columnNumber; i++ ) { + assertEquals( columnNames[i], table.getColumn( i + 1 ).getName()); + } + } + + @Entity + public static class Employee { + + @Id + @GeneratedValue( + strategy = GenerationType.AUTO + ) + private Long id; + + private String name; + + @Embedded + private BankAccounts bankAccounts = new BankAccounts(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public BankAccounts getBankAccounts() { + return bankAccounts; + } + + public void setBankAccounts(BankAccounts bankAccounts) { + this.bankAccounts = bankAccounts; + } + + } + + @Embeddable + public static class BankAccounts { + + @ElementCollection(fetch = FetchType.LAZY) + private List accounts = new ArrayList<>(); + + public List getAccounts() { + return this.accounts; + } + } + + @Embeddable + public static class BankAccount { + + private String bankName; + + private String accountNumber; + + @ManyToOne(fetch = FetchType.LAZY) + private WebUser verificationUser; + + public String getBankName() { + return bankName; + } + public void setBankName(String bankName) { + this.bankName = bankName; + } + + public String getAccountNumber() { + return accountNumber; + } + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + public WebUser getVerificationUser() { + return verificationUser; + } + public void setVerificationUser(WebUser verificationUser) { + this.verificationUser = verificationUser; + } + } + + @Entity + public static class WebUser { + + @Id + @GeneratedValue( + strategy = GenerationType.AUTO + ) + private Long id; + + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } +} + +