Hibernate SVN: r19896 - in core/branches/Branch_3_5/cache-infinispan/src: test/java/org/hibernate/test/cache/infinispan and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: galder.zamarreno(a)jboss.com
Date: 2010-07-05 10:30:38 -0400 (Mon, 05 Jul 2010)
New Revision: 19896
Modified:
core/branches/Branch_3_5/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java
core/branches/Branch_3_5/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/InfinispanRegionFactoryTestCase.java
Log:
[HHH-5260] (Allow query region name specific eviction settings) Done.
Modified: core/branches/Branch_3_5/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java
===================================================================
--- core/branches/Branch_3_5/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java 2010-07-04 19:47:28 UTC (rev 19895)
+++ core/branches/Branch_3_5/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java 2010-07-05 14:30:38 UTC (rev 19896)
@@ -99,7 +99,7 @@
/**
* Name of the configuration that should be used for timestamp caches.
*
- * @see #DEF_TS_RESOURCE
+ * @see #DEF_TIMESTAMPS_RESOURCE
*/
public static final String TIMESTAMPS_CACHE_RESOURCE_PROP = PREFIX + TIMESTAMPS_KEY + CONFIG_SUFFIX;
@@ -113,7 +113,7 @@
public static final String QUERY_CACHE_RESOURCE_PROP = PREFIX + QUERY_KEY + CONFIG_SUFFIX;
/**
- * Default value for {@link #INFINISPAN_RESOURCE_PROP}. Specifies the "infinispan-configs.xml" file in this package.
+ * Default value for {@link #INFINISPAN_CONFIG_RESOURCE_PROP}. Specifies the "infinispan-configs.xml" file in this package.
*/
public static final String DEF_INFINISPAN_CONFIG_RESOURCE = "org/hibernate/cache/infinispan/builder/infinispan-configs.xml";
@@ -183,8 +183,8 @@
public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties)
throws CacheException {
if (log.isDebugEnabled()) log.debug("Building query results cache region [" + regionName + "]");
- String cacheName = typeOverrides.get(QUERY_KEY).getCacheName();
- CacheAdapter cacheAdapter = CacheAdapterImpl.newInstance(manager.getCache(cacheName));
+ Cache cache = getCache(regionName, QUERY_KEY, properties);
+ CacheAdapter cacheAdapter = CacheAdapterImpl.newInstance(cache);
QueryResultsRegionImpl region = new QueryResultsRegionImpl(cacheAdapter, regionName, properties, transactionManager, this);
region.start();
return region;
Modified: core/branches/Branch_3_5/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/InfinispanRegionFactoryTestCase.java
===================================================================
--- core/branches/Branch_3_5/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/InfinispanRegionFactoryTestCase.java 2010-07-04 19:47:28 UTC (rev 19895)
+++ core/branches/Branch_3_5/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/InfinispanRegionFactoryTestCase.java 2010-07-05 14:30:38 UTC (rev 19896)
@@ -415,6 +415,32 @@
}
}
+ public void testBuildQueryRegionWithCustomRegionName() {
+ final String queryRegionName = "myquery";
+ Properties p = new Properties();
+ InfinispanRegionFactory factory = new InfinispanRegionFactory();
+ p.setProperty("hibernate.cache.infinispan.myquery.cfg", "timestamps-none-eviction");
+ p.setProperty("hibernate.cache.infinispan.myquery.eviction.strategy", "FIFO");
+ p.setProperty("hibernate.cache.infinispan.myquery.eviction.wake_up_interval", "2222");
+ p.setProperty("hibernate.cache.infinispan.myquery.eviction.max_entries", "11111");
+ factory.start(null, p);
+ CacheManager manager = factory.getCacheManager();
+ manager.getGlobalConfiguration().setTransportClass(null);
+ try {
+ assertTrue(factory.getDefinedConfigurations().contains("local-query"));
+ QueryResultsRegionImpl region = (QueryResultsRegionImpl) factory.buildQueryResultsRegion(queryRegionName, p);
+ assertNotNull(factory.getTypeOverrides().get(queryRegionName));
+ assertTrue(factory.getDefinedConfigurations().contains(queryRegionName));
+ CacheAdapter cache = region.getCacheAdapter();
+ Configuration cacheCfg = cache.getConfiguration();
+ assertEquals(EvictionStrategy.FIFO, cacheCfg.getEvictionStrategy());
+ assertEquals(2222, cacheCfg.getEvictionWakeUpInterval());
+ assertEquals(11111, cacheCfg.getEvictionMaxEntries());
+ } finally {
+ factory.stop();
+ }
+ }
+
public void testEnableStatistics() {
Properties p = new Properties();
p.setProperty("hibernate.cache.infinispan.statistics", "true");
14 years, 4 months
Hibernate SVN: r19895 - core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined.
by hibernate-commits@lists.jboss.org
Author: sharathjreddy
Date: 2010-07-04 15:47:28 -0400 (Sun, 04 Jul 2010)
New Revision: 19895
Added:
core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Account.java
core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Client.java
core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Person.java
Modified:
core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/JoinedSubclassTest.java
Log:
HHH-4250 : @ManyToOne - @OneToMany doesn't work with @Inheritance(strategy= InheritanceType.JOINED)
Added: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Account.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Account.java (rev 0)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Account.java 2010-07-04 19:47:28 UTC (rev 19895)
@@ -0,0 +1,106 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.test.annotations.inheritance.joined;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "ACCOUNT")
+public class Account implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private int id;
+
+ private String number;
+
+ @OneToMany(mappedBy="account")
+ private Set<Client> clients;
+
+ private double balance;
+
+ public Account() {
+ }
+
+ public int getId() {
+ return this.id;
+ }
+
+ @SuppressWarnings("unused")
+ private void setId(int id) {
+ this.id = id;
+ }
+
+ public String getNumber() {
+ return this.number;
+ }
+
+ public void setNumber(String number) {
+ this.number = number;
+ }
+
+ public double getBalance() {
+ return balance;
+ }
+
+ public void setBalance(double balance) {
+ this.balance = balance;
+ }
+
+ public void addClient(Client c) {
+ if (clients == null) {
+ clients = new HashSet<Client>();
+ }
+ clients.add(c);
+ c.setAccount(this);
+ }
+
+
+ public Set<Client> getClients() {
+ return clients;
+ }
+
+ public void setClients(Set<Client> clients) {
+ this.clients = clients;
+ }
+
+
+
+
+
+}
Added: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Client.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Client.java (rev 0)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Client.java 2010-07-04 19:47:28 UTC (rev 19895)
@@ -0,0 +1,93 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.test.annotations.inheritance.joined;
+
+import java.io.Serializable;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "CLIENT")
+public class Client extends Person implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private String street;
+
+ private String code;
+
+ private String city;
+
+ @ManyToOne(fetch = FetchType.EAGER)
+ @JoinTable(name = "CLIENT_ACCOUNT",
+ joinColumns = {@JoinColumn(name = "FK_CLIENT", referencedColumnName = "ID")},
+ inverseJoinColumns = {@JoinColumn(name = "FK_ACCOUNT", referencedColumnName = "ID")})
+ private Account account;
+
+
+
+ public Account getAccount() {
+ return account;
+ }
+
+ public void setAccount(Account account) {
+ this.account = account;
+ }
+
+ public Client() {
+ super();
+ }
+
+ public String getStreet() {
+ return street;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+}
Modified: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/JoinedSubclassTest.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/JoinedSubclassTest.java 2010-07-04 19:44:44 UTC (rev 19894)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/JoinedSubclassTest.java 2010-07-04 19:47:28 UTC (rev 19895)
@@ -1,7 +1,9 @@
//$Id$
package org.hibernate.test.annotations.inheritance.joined;
+import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
@@ -122,7 +124,49 @@
transaction.commit();
session.close();
}
+
+ //HHH-4250 : @ManyToOne - @OneToMany doesn't work with @Inheritance(strategy= InheritanceType.JOINED)
+ public void testManyToOneWithJoinTable() {
+ Session s = openSession();
+ Transaction tx = s.beginTransaction();
+
+ Client c1 = new Client();
+ c1.setFirstname("Firstname1");
+ c1.setName("Name1");
+ c1.setCode("1234");
+ c1.setStreet("Street1");
+ c1.setCity("City1");
+
+ Account a1 = new Account();
+ a1.setNumber("1000");
+ a1.setBalance(5000.0);
+
+ a1.addClient(c1);
+
+ s.persist(c1);
+ s.persist(a1);
+
+ s.flush();
+ s.clear();
+
+ c1 = (Client) s.load(Client.class, c1.getId());
+ assertEquals(5000.0, c1.getAccount().getBalance());
+
+ s.flush();
+ s.clear();
+
+ a1 = (Account) s.load(Account.class,a1.getId());
+ Set<Client> clients = a1.getClients();
+ assertEquals(1, clients.size());
+ Iterator<Client> it = clients.iterator();
+ c1 = it.next();
+ assertEquals("Name1", c1.getName());
+
+ tx.rollback();
+ s.close();
+ }
+
// public void testManyToOneAndJoin() throws Exception {
// Session session = openSession();
// Transaction transaction = session.beginTransaction();
@@ -168,6 +212,8 @@
Sweater.class,
EventInformation.class,
Alarm.class,
+ Client.class,
+ Account.class
//Asset.class,
//Parent.class,
//PropertyAsset.class,
Added: core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Person.java
===================================================================
--- core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Person.java (rev 0)
+++ core/trunk/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Person.java 2010-07-04 19:47:28 UTC (rev 19895)
@@ -0,0 +1,80 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.test.annotations.inheritance.joined;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.Table;
+
+@Entity
+@Inheritance(strategy = InheritanceType.JOINED)
+@Table(name = "PERSON")
+public class Person {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private int id;
+
+ private String name;
+
+ private String firtsname;
+
+ public Person() {
+
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getFirstname() {
+ return firtsname;
+ }
+
+ public void setFirstname(String firstname) {
+ this.firtsname = firstname;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+}
+
14 years, 5 months
Hibernate SVN: r19894 - core/trunk/core/src/main/java/org/hibernate/persister/entity.
by hibernate-commits@lists.jboss.org
Author: sharathjreddy
Date: 2010-07-04 15:44:44 -0400 (Sun, 04 Jul 2010)
New Revision: 19894
Modified:
core/trunk/core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java
Log:
HHH-4250 : @ManyToOne - @OneToMany doesn't work with @Inheritance(strategy= InheritanceType.JOINED)
Modified: core/trunk/core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java 2010-07-04 17:35:41 UTC (rev 19893)
+++ core/trunk/core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java 2010-07-04 19:44:44 UTC (rev 19894)
@@ -1,635 +1,781 @@
-/*
- * Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
- *
- * 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.persister.entity;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import org.hibernate.AssertionFailure;
-import org.hibernate.Hibernate;
-import org.hibernate.HibernateException;
-import org.hibernate.MappingException;
-import org.hibernate.QueryException;
-import org.hibernate.cache.access.EntityRegionAccessStrategy;
-import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
-import org.hibernate.engine.Mapping;
-import org.hibernate.engine.SessionFactoryImplementor;
-import org.hibernate.engine.Versioning;
-import org.hibernate.mapping.Column;
-import org.hibernate.mapping.KeyValue;
-import org.hibernate.mapping.PersistentClass;
-import org.hibernate.mapping.Property;
-import org.hibernate.mapping.Selectable;
-import org.hibernate.mapping.Subclass;
-import org.hibernate.mapping.Table;
-import org.hibernate.sql.CaseFragment;
-import org.hibernate.sql.SelectFragment;
-import org.hibernate.type.AbstractType;
-import org.hibernate.type.Type;
-import org.hibernate.util.ArrayHelper;
-
-/**
- * An <tt>EntityPersister</tt> implementing the normalized "table-per-subclass"
- * mapping strategy
- *
- * @author Gavin King
- */
-public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
-
- // the class hierarchy structure
- private final int tableSpan;
- private final String[] tableNames;
- private final String[] naturalOrderTableNames;
- private final String[][] tableKeyColumns;
- private final String[][] tableKeyColumnReaders;
- private final String[][] tableKeyColumnReaderTemplates;
- private final String[][] naturalOrderTableKeyColumns;
- private final String[][] naturalOrderTableKeyColumnReaders;
- private final String[][] naturalOrderTableKeyColumnReaderTemplates;
- private final boolean[] naturalOrderCascadeDeleteEnabled;
-
- private final String[] spaces;
-
- private final String[] subclassClosure;
-
- private final String[] subclassTableNameClosure;
- private final String[][] subclassTableKeyColumnClosure;
- private final boolean[] isClassOrSuperclassTable;
-
- // properties of this class, including inherited properties
- private final int[] naturalOrderPropertyTableNumbers;
- private final int[] propertyTableNumbers;
-
- // the closure of all properties in the entire hierarchy including
- // subclasses and superclasses of this class
- private final int[] subclassPropertyTableNumberClosure;
-
- // the closure of all columns used by the entire hierarchy including
- // subclasses and superclasses of this class
- private final int[] subclassColumnTableNumberClosure;
- private final int[] subclassFormulaTableNumberClosure;
-
- // subclass discrimination works by assigning particular
- // values to certain combinations of null primary key
- // values in the outer join using an SQL CASE
- private final Map subclassesByDiscriminatorValue = new HashMap();
- private final String[] discriminatorValues;
- private final String[] notNullColumnNames;
- private final int[] notNullColumnTableNumbers;
-
- private final String[] constraintOrderedTableNames;
- private final String[][] constraintOrderedKeyColumnNames;
-
- private final String discriminatorSQLString;
-
- //INITIALIZATION:
-
- public JoinedSubclassEntityPersister(
- final PersistentClass persistentClass,
- final EntityRegionAccessStrategy cacheAccessStrategy,
- final SessionFactoryImplementor factory,
- final Mapping mapping) throws HibernateException {
-
- super( persistentClass, cacheAccessStrategy, factory );
-
- // DISCRIMINATOR
-
- final Object discriminatorValue;
- if ( persistentClass.isPolymorphic() ) {
- try {
- discriminatorValue = new Integer( persistentClass.getSubclassId() );
- discriminatorSQLString = discriminatorValue.toString();
- }
- catch (Exception e) {
- throw new MappingException("Could not format discriminator value to SQL string", e );
- }
- }
- else {
- discriminatorValue = null;
- discriminatorSQLString = null;
- }
-
- if ( optimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION ) {
- throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" );
- }
-
- //MULTITABLES
-
- final int idColumnSpan = getIdentifierColumnSpan();
-
- ArrayList tables = new ArrayList();
- ArrayList keyColumns = new ArrayList();
- ArrayList keyColumnReaders = new ArrayList();
- ArrayList keyColumnReaderTemplates = new ArrayList();
- ArrayList cascadeDeletes = new ArrayList();
- Iterator titer = persistentClass.getTableClosureIterator();
- Iterator kiter = persistentClass.getKeyClosureIterator();
- while ( titer.hasNext() ) {
- Table tab = (Table) titer.next();
- KeyValue key = (KeyValue) kiter.next();
- String tabname = tab.getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
- );
- tables.add(tabname);
- String[] keyCols = new String[idColumnSpan];
- String[] keyColReaders = new String[idColumnSpan];
- String[] keyColReaderTemplates = new String[idColumnSpan];
- Iterator citer = key.getColumnIterator();
- for ( int k=0; k<idColumnSpan; k++ ) {
- Column column = (Column) citer.next();
- keyCols[k] = column.getQuotedName( factory.getDialect() );
- keyColReaders[k] = column.getReadExpr( factory.getDialect() );
- keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
- }
- keyColumns.add(keyCols);
- keyColumnReaders.add(keyColReaders);
- keyColumnReaderTemplates.add(keyColReaderTemplates);
- cascadeDeletes.add( new Boolean( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ) );
- }
- naturalOrderTableNames = ArrayHelper.toStringArray(tables);
- naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray(keyColumns);
- naturalOrderTableKeyColumnReaders = ArrayHelper.to2DStringArray(keyColumnReaders);
- naturalOrderTableKeyColumnReaderTemplates = ArrayHelper.to2DStringArray(keyColumnReaderTemplates);
- naturalOrderCascadeDeleteEnabled = ArrayHelper.toBooleanArray(cascadeDeletes);
-
- ArrayList subtables = new ArrayList();
- ArrayList isConcretes = new ArrayList();
- keyColumns = new ArrayList();
- titer = persistentClass.getSubclassTableClosureIterator();
- while ( titer.hasNext() ) {
- Table tab = (Table) titer.next();
- isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassTable(tab) ) );
- String tabname = tab.getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
- );
- subtables.add(tabname);
- String[] key = new String[idColumnSpan];
- Iterator citer = tab.getPrimaryKey().getColumnIterator();
- for ( int k=0; k<idColumnSpan; k++ ) {
- key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
- }
- keyColumns.add(key);
- }
- subclassTableNameClosure = ArrayHelper.toStringArray(subtables);
- subclassTableKeyColumnClosure = ArrayHelper.to2DStringArray(keyColumns);
- isClassOrSuperclassTable = ArrayHelper.toBooleanArray(isConcretes);
-
- constraintOrderedTableNames = new String[subclassTableNameClosure.length];
- constraintOrderedKeyColumnNames = new String[subclassTableNameClosure.length][];
- int currentPosition = 0;
- for ( int i = subclassTableNameClosure.length - 1; i >= 0 ; i--, currentPosition++ ) {
- constraintOrderedTableNames[currentPosition] = subclassTableNameClosure[i];
- constraintOrderedKeyColumnNames[currentPosition] = subclassTableKeyColumnClosure[i];
- }
-
- tableSpan = naturalOrderTableNames.length;
- tableNames = reverse(naturalOrderTableNames);
- tableKeyColumns = reverse(naturalOrderTableKeyColumns);
- tableKeyColumnReaders = reverse(naturalOrderTableKeyColumnReaders);
- tableKeyColumnReaderTemplates = reverse(naturalOrderTableKeyColumnReaderTemplates);
- reverse(subclassTableNameClosure, tableSpan);
- reverse(subclassTableKeyColumnClosure, tableSpan);
-
- spaces = ArrayHelper.join(
- tableNames,
- ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
- );
-
- // Custom sql
- customSQLInsert = new String[tableSpan];
- customSQLUpdate = new String[tableSpan];
- customSQLDelete = new String[tableSpan];
- insertCallable = new boolean[tableSpan];
- updateCallable = new boolean[tableSpan];
- deleteCallable = new boolean[tableSpan];
- insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
- updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
- deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
-
- PersistentClass pc = persistentClass;
- int jk = tableSpan-1;
- while (pc!=null) {
- customSQLInsert[jk] = pc.getCustomSQLInsert();
- insertCallable[jk] = customSQLInsert[jk] != null && pc.isCustomInsertCallable();
- insertResultCheckStyles[jk] = pc.getCustomSQLInsertCheckStyle() == null
- ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[jk], insertCallable[jk] )
- : pc.getCustomSQLInsertCheckStyle();
- customSQLUpdate[jk] = pc.getCustomSQLUpdate();
- updateCallable[jk] = customSQLUpdate[jk] != null && pc.isCustomUpdateCallable();
- updateResultCheckStyles[jk] = pc.getCustomSQLUpdateCheckStyle() == null
- ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[jk], updateCallable[jk] )
- : pc.getCustomSQLUpdateCheckStyle();
- customSQLDelete[jk] = pc.getCustomSQLDelete();
- deleteCallable[jk] = customSQLDelete[jk] != null && pc.isCustomDeleteCallable();
- deleteResultCheckStyles[jk] = pc.getCustomSQLDeleteCheckStyle() == null
- ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[jk], deleteCallable[jk] )
- : pc.getCustomSQLDeleteCheckStyle();
- jk--;
- pc = pc.getSuperclass();
- }
- if ( jk != -1 ) {
- throw new AssertionFailure( "Tablespan does not match height of joined-subclass hiearchy." );
- }
-
- // PROPERTIES
-
- int hydrateSpan = getPropertySpan();
- naturalOrderPropertyTableNumbers = new int[hydrateSpan];
- propertyTableNumbers = new int[hydrateSpan];
- Iterator iter = persistentClass.getPropertyClosureIterator();
- int i=0;
- while( iter.hasNext() ) {
- Property prop = (Property) iter.next();
- String tabname = prop.getValue().getTable().getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
- );
- propertyTableNumbers[i] = getTableId(tabname, tableNames);
- naturalOrderPropertyTableNumbers[i] = getTableId(tabname, naturalOrderTableNames);
- i++;
- }
-
- // subclass closure properties
-
- //TODO: code duplication with SingleTableEntityPersister
-
- ArrayList columnTableNumbers = new ArrayList();
- ArrayList formulaTableNumbers = new ArrayList();
- ArrayList propTableNumbers = new ArrayList();
-
- iter = persistentClass.getSubclassPropertyClosureIterator();
- while ( iter.hasNext() ) {
- Property prop = (Property) iter.next();
- Table tab = prop.getValue().getTable();
- String tabname = tab.getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
- );
- Integer tabnum = new Integer( getTableId(tabname, subclassTableNameClosure) );
- propTableNumbers.add(tabnum);
-
- Iterator citer = prop.getColumnIterator();
- while ( citer.hasNext() ) {
- Selectable thing = (Selectable) citer.next();
- if ( thing.isFormula() ) {
- formulaTableNumbers.add(tabnum);
- }
- else {
- columnTableNumbers.add(tabnum);
- }
- }
-
- }
-
- subclassColumnTableNumberClosure = ArrayHelper.toIntArray(columnTableNumbers);
- subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propTableNumbers);
- subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaTableNumbers);
-
- // SUBCLASSES
-
- int subclassSpan = persistentClass.getSubclassSpan() + 1;
- subclassClosure = new String[subclassSpan];
- subclassClosure[subclassSpan-1] = getEntityName();
- if ( persistentClass.isPolymorphic() ) {
- subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
- discriminatorValues = new String[subclassSpan];
- discriminatorValues[subclassSpan-1] = discriminatorSQLString;
- notNullColumnTableNumbers = new int[subclassSpan];
- final int id = getTableId(
- persistentClass.getTable().getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
- ),
- subclassTableNameClosure
- );
- notNullColumnTableNumbers[subclassSpan-1] = id;
- notNullColumnNames = new String[subclassSpan];
- notNullColumnNames[subclassSpan-1] = subclassTableKeyColumnClosure[id][0]; //( (Column) model.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
- }
- else {
- discriminatorValues = null;
- notNullColumnTableNumbers = null;
- notNullColumnNames = null;
- }
-
- iter = persistentClass.getSubclassIterator();
- int k=0;
- while ( iter.hasNext() ) {
- Subclass sc = (Subclass) iter.next();
- subclassClosure[k] = sc.getEntityName();
- try {
- if ( persistentClass.isPolymorphic() ) {
- // we now use subclass ids that are consistent across all
- // persisters for a class hierarchy, so that the use of
- // "foo.class = Bar" works in HQL
- Integer subclassId = new Integer( sc.getSubclassId() );//new Integer(k+1);
- subclassesByDiscriminatorValue.put( subclassId, sc.getEntityName() );
- discriminatorValues[k] = subclassId.toString();
- int id = getTableId(
- sc.getTable().getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
- ),
- subclassTableNameClosure
- );
- notNullColumnTableNumbers[k] = id;
- notNullColumnNames[k] = subclassTableKeyColumnClosure[id][0]; //( (Column) sc.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
- }
- }
- catch (Exception e) {
- throw new MappingException("Error parsing discriminator value", e );
- }
- k++;
- }
-
- initLockers();
-
- initSubclassPropertyAliasesMap(persistentClass);
-
- postConstruct(mapping);
-
- }
-
- /*public void postInstantiate() throws MappingException {
- super.postInstantiate();
- //TODO: other lock modes?
- loader = createEntityLoader(LockMode.NONE, CollectionHelper.EMPTY_MAP);
- }*/
-
- public String getSubclassPropertyTableName(int i) {
- return subclassTableNameClosure[ subclassPropertyTableNumberClosure[i] ];
- }
-
- public Type getDiscriminatorType() {
- return Hibernate.INTEGER;
- }
-
- public String getDiscriminatorSQLValue() {
- return discriminatorSQLString;
- }
-
-
- public String getSubclassForDiscriminatorValue(Object value) {
- return (String) subclassesByDiscriminatorValue.get(value);
- }
-
- public Serializable[] getPropertySpaces() {
- return spaces; // don't need subclass tables, because they can't appear in conditions
- }
-
-
- protected String getTableName(int j) {
- return naturalOrderTableNames[j];
- }
-
- protected String[] getKeyColumns(int j) {
- return naturalOrderTableKeyColumns[j];
- }
-
- protected boolean isTableCascadeDeleteEnabled(int j) {
- return naturalOrderCascadeDeleteEnabled[j];
- }
-
- protected boolean isPropertyOfTable(int property, int j) {
- return naturalOrderPropertyTableNumbers[property]==j;
- }
-
- /**
- * Load an instance using either the <tt>forUpdateLoader</tt> or the outer joining <tt>loader</tt>,
- * depending upon the value of the <tt>lock</tt> parameter
- */
- /*public Object load(Serializable id, Object optionalObject, LockMode lockMode, SessionImplementor session)
- throws HibernateException {
-
- if ( log.isTraceEnabled() ) log.trace( "Materializing entity: " + MessageHelper.infoString(this, id) );
-
- final UniqueEntityLoader loader = hasQueryLoader() ?
- getQueryLoader() :
- this.loader;
- try {
-
- final Object result = loader.load(id, optionalObject, session);
-
- if (result!=null) lock(id, getVersion(result), result, lockMode, session);
-
- return result;
-
- }
- catch (SQLException sqle) {
- throw new JDBCException( "could not load by id: " + MessageHelper.infoString(this, id), sqle );
- }
- }*/
-
- private static final void reverse(Object[] objects, int len) {
- Object[] temp = new Object[len];
- for (int i=0; i<len; i++) {
- temp[i] = objects[len-i-1];
- }
- for (int i=0; i<len; i++) {
- objects[i] = temp[i];
- }
- }
-
- private static final String[] reverse(String[] objects) {
- int len = objects.length;
- String[] temp = new String[len];
- for (int i=0; i<len; i++) {
- temp[i] = objects[len-i-1];
- }
- return temp;
- }
-
- private static final String[][] reverse(String[][] objects) {
- int len = objects.length;
- String[][] temp = new String[len][];
- for (int i=0; i<len; i++) {
- temp[i] = objects[len-i-1];
- }
- return temp;
- }
-
- public String fromTableFragment(String alias) {
- return getTableName() + ' ' + alias;
- }
-
- public String getTableName() {
- return tableNames[0];
- }
-
- private static int getTableId(String tableName, String[] tables) {
- for ( int j=0; j<tables.length; j++ ) {
- if ( tableName.equals( tables[j] ) ) {
- return j;
- }
- }
- throw new AssertionFailure("Table " + tableName + " not found");
- }
-
- public void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) {
- if ( hasSubclasses() ) {
- select.setExtraSelectList( discriminatorFragment(name), getDiscriminatorAlias() );
- }
- }
-
- private CaseFragment discriminatorFragment(String alias) {
- CaseFragment cases = getFactory().getDialect().createCaseFragment();
-
- for ( int i=0; i<discriminatorValues.length; i++ ) {
- cases.addWhenColumnNotNull(
- generateTableAlias( alias, notNullColumnTableNumbers[i] ),
- notNullColumnNames[i],
- discriminatorValues[i]
- );
- }
-
- return cases;
- }
-
- public String filterFragment(String alias) {
- return hasWhere() ?
- " and " + getSQLWhereString( generateFilterConditionAlias( alias ) ) :
- "";
- }
-
- public String generateFilterConditionAlias(String rootAlias) {
- return generateTableAlias( rootAlias, tableSpan-1 );
- }
-
- public String[] getIdentifierColumnNames() {
- return tableKeyColumns[0];
- }
-
- public String[] getIdentifierColumnReaderTemplates() {
- return tableKeyColumnReaderTemplates[0];
- }
-
- public String[] getIdentifierColumnReaders() {
- return tableKeyColumnReaders[0];
- }
-
- public String[] toColumns(String alias, String propertyName) throws QueryException {
-
- if ( ENTITY_CLASS.equals(propertyName) ) {
- // This doesn't actually seem to work but it *might*
- // work on some dbs. Also it doesn't work if there
- // are multiple columns of results because it
- // is not accounting for the suffix:
- // return new String[] { getDiscriminatorColumnName() };
-
- return new String[] { discriminatorFragment(alias).toFragmentString() };
- }
- else {
- return super.toColumns(alias, propertyName);
- }
-
- }
-
- protected int[] getPropertyTableNumbersInSelect() {
- return propertyTableNumbers;
- }
-
- protected int getSubclassPropertyTableNumber(int i) {
- return subclassPropertyTableNumberClosure[i];
- }
-
- public int getTableSpan() {
- return tableSpan;
- }
-
- public boolean isMultiTable() {
- return true;
- }
-
- protected int[] getSubclassColumnTableNumberClosure() {
- return subclassColumnTableNumberClosure;
- }
-
- protected int[] getSubclassFormulaTableNumberClosure() {
- return subclassFormulaTableNumberClosure;
- }
-
- protected int[] getPropertyTableNumbers() {
- return naturalOrderPropertyTableNumbers;
- }
-
- protected String[] getSubclassTableKeyColumns(int j) {
- return subclassTableKeyColumnClosure[j];
- }
-
- public String getSubclassTableName(int j) {
- return subclassTableNameClosure[j];
- }
-
- public int getSubclassTableSpan() {
- return subclassTableNameClosure.length;
- }
-
- protected boolean isClassOrSuperclassTable(int j) {
- return isClassOrSuperclassTable[j];
- }
-
- public String getPropertyTableName(String propertyName) {
- Integer index = getEntityMetamodel().getPropertyIndexOrNull(propertyName);
- if ( index == null ) {
- return null;
- }
- return tableNames[ propertyTableNumbers[ index.intValue() ] ];
- }
-
- public String[] getConstraintOrderedTableNameClosure() {
- return constraintOrderedTableNames;
- }
-
- public String[][] getContraintOrderedTableKeyColumnClosure() {
- return constraintOrderedKeyColumnNames;
- }
-
- public String getRootTableName() {
- return naturalOrderTableNames[0];
- }
-
- public String getRootTableAlias(String drivingAlias) {
- return generateTableAlias( drivingAlias, getTableId( getRootTableName(), tableNames ) );
- }
-
- public Declarer getSubclassPropertyDeclarer(String propertyPath) {
- if ( "class".equals( propertyPath ) ) {
- // special case where we need to force incloude all subclass joins
- return Declarer.SUBCLASS;
- }
- return super.getSubclassPropertyDeclarer( propertyPath );
- }
-}
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ *
+ * 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.persister.entity;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.Versioning;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.KeyValue;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.Selectable;
+import org.hibernate.mapping.Subclass;
+import org.hibernate.mapping.Table;
+import org.hibernate.sql.CaseFragment;
+import org.hibernate.sql.SelectFragment;
+import org.hibernate.type.AbstractType;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * An <tt>EntityPersister</tt> implementing the normalized "table-per-subclass"
+ * mapping strategy
+ *
+ * @author Gavin King
+ */
+public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
+
+ // the class hierarchy structure
+ private final int tableSpan;
+ private final String[] tableNames;
+ private final String[] naturalOrderTableNames;
+ private final String[][] tableKeyColumns;
+ private final String[][] tableKeyColumnReaders;
+ private final String[][] tableKeyColumnReaderTemplates;
+ private final String[][] naturalOrderTableKeyColumns;
+ private final String[][] naturalOrderTableKeyColumnReaders;
+ private final String[][] naturalOrderTableKeyColumnReaderTemplates;
+ private final boolean[] naturalOrderCascadeDeleteEnabled;
+
+ private final String[] spaces;
+
+ private final String[] subclassClosure;
+
+ private final String[] subclassTableNameClosure;
+ private final String[][] subclassTableKeyColumnClosure;
+ private final boolean[] isClassOrSuperclassTable;
+
+ // properties of this class, including inherited properties
+ private final int[] naturalOrderPropertyTableNumbers;
+ private final int[] propertyTableNumbers;
+
+ // the closure of all properties in the entire hierarchy including
+ // subclasses and superclasses of this class
+ private final int[] subclassPropertyTableNumberClosure;
+
+ // the closure of all columns used by the entire hierarchy including
+ // subclasses and superclasses of this class
+ private final int[] subclassColumnTableNumberClosure;
+ private final int[] subclassFormulaTableNumberClosure;
+
+ private final boolean[] subclassTableSequentialSelect;
+ private final boolean[] subclassTableIsLazyClosure;
+
+ // subclass discrimination works by assigning particular
+ // values to certain combinations of null primary key
+ // values in the outer join using an SQL CASE
+ private final Map subclassesByDiscriminatorValue = new HashMap();
+ private final String[] discriminatorValues;
+ private final String[] notNullColumnNames;
+ private final int[] notNullColumnTableNumbers;
+
+ private final String[] constraintOrderedTableNames;
+ private final String[][] constraintOrderedKeyColumnNames;
+
+ private final String discriminatorSQLString;
+
+ //INITIALIZATION:
+
+ public JoinedSubclassEntityPersister(
+ final PersistentClass persistentClass,
+ final EntityRegionAccessStrategy cacheAccessStrategy,
+ final SessionFactoryImplementor factory,
+ final Mapping mapping) throws HibernateException {
+
+ super( persistentClass, cacheAccessStrategy, factory );
+
+ // DISCRIMINATOR
+
+ final Object discriminatorValue;
+ if ( persistentClass.isPolymorphic() ) {
+ try {
+ discriminatorValue = new Integer( persistentClass.getSubclassId() );
+ discriminatorSQLString = discriminatorValue.toString();
+ }
+ catch (Exception e) {
+ throw new MappingException("Could not format discriminator value to SQL string", e );
+ }
+ }
+ else {
+ discriminatorValue = null;
+ discriminatorSQLString = null;
+ }
+
+ if ( optimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION ) {
+ throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" );
+ }
+
+ //MULTITABLES
+
+ final int idColumnSpan = getIdentifierColumnSpan();
+
+ ArrayList tables = new ArrayList();
+ ArrayList keyColumns = new ArrayList();
+ ArrayList keyColumnReaders = new ArrayList();
+ ArrayList keyColumnReaderTemplates = new ArrayList();
+ ArrayList cascadeDeletes = new ArrayList();
+ Iterator titer = persistentClass.getTableClosureIterator();
+ Iterator kiter = persistentClass.getKeyClosureIterator();
+ while ( titer.hasNext() ) {
+ Table tab = (Table) titer.next();
+ KeyValue key = (KeyValue) kiter.next();
+ String tabname = tab.getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ );
+ tables.add(tabname);
+ String[] keyCols = new String[idColumnSpan];
+ String[] keyColReaders = new String[idColumnSpan];
+ String[] keyColReaderTemplates = new String[idColumnSpan];
+ Iterator citer = key.getColumnIterator();
+ for ( int k=0; k<idColumnSpan; k++ ) {
+ Column column = (Column) citer.next();
+ keyCols[k] = column.getQuotedName( factory.getDialect() );
+ keyColReaders[k] = column.getReadExpr( factory.getDialect() );
+ keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
+ }
+ keyColumns.add(keyCols);
+ keyColumnReaders.add(keyColReaders);
+ keyColumnReaderTemplates.add(keyColReaderTemplates);
+ cascadeDeletes.add( new Boolean( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ) );
+ }
+
+ //Span of the tables directly mapped by this entity and super-classes, if any
+ int coreTableSpan = tables.size();
+
+ Iterator joinIter = persistentClass.getJoinClosureIterator();
+ while ( joinIter.hasNext() ) {
+ Join join = (Join) joinIter.next();
+
+ Table tab = join.getTable();
+
+ String tabname = tab.getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ );
+ tables.add(tabname);
+
+ KeyValue key = join.getKey();
+ int joinIdColumnSpan = key.getColumnSpan();
+
+ String[] keyCols = new String[joinIdColumnSpan];
+ String[] keyColReaders = new String[joinIdColumnSpan];
+ String[] keyColReaderTemplates = new String[joinIdColumnSpan];
+
+ Iterator citer = key.getColumnIterator();
+
+ for ( int k=0; k<joinIdColumnSpan; k++ ) {
+ Column column = (Column) citer.next();
+ keyCols[k] = column.getQuotedName( factory.getDialect() );
+ keyColReaders[k] = column.getReadExpr( factory.getDialect() );
+ keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
+ }
+ keyColumns.add(keyCols);
+ keyColumnReaders.add(keyColReaders);
+ keyColumnReaderTemplates.add(keyColReaderTemplates);
+ cascadeDeletes.add( new Boolean( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ) );
+ }
+
+ naturalOrderTableNames = ArrayHelper.toStringArray(tables);
+ naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray(keyColumns);
+ naturalOrderTableKeyColumnReaders = ArrayHelper.to2DStringArray(keyColumnReaders);
+ naturalOrderTableKeyColumnReaderTemplates = ArrayHelper.to2DStringArray(keyColumnReaderTemplates);
+ naturalOrderCascadeDeleteEnabled = ArrayHelper.toBooleanArray(cascadeDeletes);
+
+ ArrayList subtables = new ArrayList();
+ ArrayList isConcretes = new ArrayList();
+ ArrayList isDeferreds = new ArrayList();
+ ArrayList isLazies = new ArrayList();
+
+ keyColumns = new ArrayList();
+ titer = persistentClass.getSubclassTableClosureIterator();
+ while ( titer.hasNext() ) {
+ Table tab = (Table) titer.next();
+ isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassTable(tab) ) );
+ isDeferreds.add(Boolean.FALSE);
+ isLazies.add(Boolean.FALSE);
+ String tabname = tab.getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ );
+ subtables.add(tabname);
+ String[] key = new String[idColumnSpan];
+ Iterator citer = tab.getPrimaryKey().getColumnIterator();
+ for ( int k=0; k<idColumnSpan; k++ ) {
+ key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
+ }
+ keyColumns.add(key);
+ }
+
+ //Add joins
+ joinIter = persistentClass.getSubclassJoinClosureIterator();
+ while ( joinIter.hasNext() ) {
+ Join join = (Join) joinIter.next();
+
+ Table tab = join.getTable();
+
+ isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassTable(tab) ) );
+ isDeferreds.add( new Boolean( join.isSequentialSelect() ) );
+ isLazies.add(new Boolean(join.isLazy()));
+
+ String tabname = tab.getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ );
+ subtables.add(tabname);
+ String[] key = new String[idColumnSpan];
+ Iterator citer = tab.getPrimaryKey().getColumnIterator();
+ for ( int k=0; k<idColumnSpan; k++ ) {
+ key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
+ }
+ keyColumns.add(key);
+
+ }
+
+ String [] naturalOrderSubclassTableNameClosure = ArrayHelper.toStringArray(subtables);
+ String[][] naturalOrderSubclassTableKeyColumnClosure = ArrayHelper.to2DStringArray(keyColumns);
+ isClassOrSuperclassTable = ArrayHelper.toBooleanArray(isConcretes);
+ subclassTableSequentialSelect = ArrayHelper.toBooleanArray(isDeferreds);
+ subclassTableIsLazyClosure = ArrayHelper.toBooleanArray(isLazies);
+
+ constraintOrderedTableNames = new String[naturalOrderSubclassTableNameClosure.length];
+ constraintOrderedKeyColumnNames = new String[naturalOrderSubclassTableNameClosure.length][];
+ int currentPosition = 0;
+ for ( int i = naturalOrderSubclassTableNameClosure.length - 1; i >= 0 ; i--, currentPosition++ ) {
+ constraintOrderedTableNames[currentPosition] = naturalOrderSubclassTableNameClosure[i];
+ constraintOrderedKeyColumnNames[currentPosition] = naturalOrderSubclassTableKeyColumnClosure[i];
+ }
+
+ /**
+ * Suppose an entity Client extends Person, mapped to the tables CLIENT and PERSON respectively.
+ * For the Client entity:
+ * naturalOrderTableNames -> PERSON, CLIENT; this reflects the sequence in which the tables are
+ * added to the meta-data when the annotated entities are processed.
+ * However, in some instances, for example when generating joins, the CLIENT table needs to be
+ * the first table as it will the driving table.
+ * tableNames -> CLIENT, PERSON
+ */
+
+ tableSpan = naturalOrderTableNames.length;
+ tableNames = reverse(naturalOrderTableNames, coreTableSpan);
+ tableKeyColumns = reverse(naturalOrderTableKeyColumns, coreTableSpan);
+ tableKeyColumnReaders = reverse(naturalOrderTableKeyColumnReaders, coreTableSpan);
+ tableKeyColumnReaderTemplates = reverse(naturalOrderTableKeyColumnReaderTemplates, coreTableSpan);
+ subclassTableNameClosure = reverse(naturalOrderSubclassTableNameClosure, coreTableSpan);
+ subclassTableKeyColumnClosure = reverse(naturalOrderSubclassTableKeyColumnClosure, coreTableSpan);
+
+ spaces = ArrayHelper.join(
+ tableNames,
+ ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
+ );
+
+ // Custom sql
+ customSQLInsert = new String[tableSpan];
+ customSQLUpdate = new String[tableSpan];
+ customSQLDelete = new String[tableSpan];
+ insertCallable = new boolean[tableSpan];
+ updateCallable = new boolean[tableSpan];
+ deleteCallable = new boolean[tableSpan];
+ insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
+ updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
+ deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
+
+ PersistentClass pc = persistentClass;
+ int jk = coreTableSpan-1;
+ while (pc!=null) {
+ customSQLInsert[jk] = pc.getCustomSQLInsert();
+ insertCallable[jk] = customSQLInsert[jk] != null && pc.isCustomInsertCallable();
+ insertResultCheckStyles[jk] = pc.getCustomSQLInsertCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[jk], insertCallable[jk] )
+ : pc.getCustomSQLInsertCheckStyle();
+ customSQLUpdate[jk] = pc.getCustomSQLUpdate();
+ updateCallable[jk] = customSQLUpdate[jk] != null && pc.isCustomUpdateCallable();
+ updateResultCheckStyles[jk] = pc.getCustomSQLUpdateCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[jk], updateCallable[jk] )
+ : pc.getCustomSQLUpdateCheckStyle();
+ customSQLDelete[jk] = pc.getCustomSQLDelete();
+ deleteCallable[jk] = customSQLDelete[jk] != null && pc.isCustomDeleteCallable();
+ deleteResultCheckStyles[jk] = pc.getCustomSQLDeleteCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[jk], deleteCallable[jk] )
+ : pc.getCustomSQLDeleteCheckStyle();
+ jk--;
+ pc = pc.getSuperclass();
+ }
+
+ if ( jk != -1 ) {
+ throw new AssertionFailure( "Tablespan does not match height of joined-subclass hiearchy." );
+ }
+
+ joinIter = persistentClass.getJoinClosureIterator();
+ int j = coreTableSpan;
+ while ( joinIter.hasNext() ) {
+ Join join = (Join) joinIter.next();
+
+ customSQLInsert[j] = join.getCustomSQLInsert();
+ insertCallable[j] = customSQLInsert[j] != null && join.isCustomInsertCallable();
+ insertResultCheckStyles[j] = join.getCustomSQLInsertCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[j], insertCallable[j] )
+ : join.getCustomSQLInsertCheckStyle();
+ customSQLUpdate[j] = join.getCustomSQLUpdate();
+ updateCallable[j] = customSQLUpdate[j] != null && join.isCustomUpdateCallable();
+ updateResultCheckStyles[j] = join.getCustomSQLUpdateCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[j], updateCallable[j] )
+ : join.getCustomSQLUpdateCheckStyle();
+ customSQLDelete[j] = join.getCustomSQLDelete();
+ deleteCallable[j] = customSQLDelete[j] != null && join.isCustomDeleteCallable();
+ deleteResultCheckStyles[j] = join.getCustomSQLDeleteCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[j], deleteCallable[j] )
+ : join.getCustomSQLDeleteCheckStyle();
+ j++;
+ }
+
+ // PROPERTIES
+ int hydrateSpan = getPropertySpan();
+ naturalOrderPropertyTableNumbers = new int[hydrateSpan];
+ propertyTableNumbers = new int[hydrateSpan];
+ Iterator iter = persistentClass.getPropertyClosureIterator();
+ int i=0;
+ while( iter.hasNext() ) {
+ Property prop = (Property) iter.next();
+ String tabname = prop.getValue().getTable().getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ );
+ propertyTableNumbers[i] = getTableId(tabname, tableNames);
+ naturalOrderPropertyTableNumbers[i] = getTableId(tabname, naturalOrderTableNames);
+ i++;
+ }
+
+ // subclass closure properties
+
+ //TODO: code duplication with SingleTableEntityPersister
+
+ ArrayList columnTableNumbers = new ArrayList();
+ ArrayList formulaTableNumbers = new ArrayList();
+ ArrayList propTableNumbers = new ArrayList();
+
+ iter = persistentClass.getSubclassPropertyClosureIterator();
+ while ( iter.hasNext() ) {
+ Property prop = (Property) iter.next();
+ Table tab = prop.getValue().getTable();
+ String tabname = tab.getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ );
+ Integer tabnum = new Integer( getTableId(tabname, subclassTableNameClosure) );
+ propTableNumbers.add(tabnum);
+
+ Iterator citer = prop.getColumnIterator();
+ while ( citer.hasNext() ) {
+ Selectable thing = (Selectable) citer.next();
+ if ( thing.isFormula() ) {
+ formulaTableNumbers.add(tabnum);
+ }
+ else {
+ columnTableNumbers.add(tabnum);
+ }
+ }
+
+ }
+
+ subclassColumnTableNumberClosure = ArrayHelper.toIntArray(columnTableNumbers);
+ subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propTableNumbers);
+ subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaTableNumbers);
+
+ // SUBCLASSES
+
+ int subclassSpan = persistentClass.getSubclassSpan() + 1;
+ subclassClosure = new String[subclassSpan];
+ subclassClosure[subclassSpan-1] = getEntityName();
+ if ( persistentClass.isPolymorphic() ) {
+ subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
+ discriminatorValues = new String[subclassSpan];
+ discriminatorValues[subclassSpan-1] = discriminatorSQLString;
+ notNullColumnTableNumbers = new int[subclassSpan];
+ final int id = getTableId(
+ persistentClass.getTable().getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ ),
+ subclassTableNameClosure
+ );
+ notNullColumnTableNumbers[subclassSpan-1] = id;
+ notNullColumnNames = new String[subclassSpan];
+ notNullColumnNames[subclassSpan-1] = subclassTableKeyColumnClosure[id][0]; //( (Column) model.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
+ }
+ else {
+ discriminatorValues = null;
+ notNullColumnTableNumbers = null;
+ notNullColumnNames = null;
+ }
+
+ iter = persistentClass.getSubclassIterator();
+ int k=0;
+ while ( iter.hasNext() ) {
+ Subclass sc = (Subclass) iter.next();
+ subclassClosure[k] = sc.getEntityName();
+ try {
+ if ( persistentClass.isPolymorphic() ) {
+ // we now use subclass ids that are consistent across all
+ // persisters for a class hierarchy, so that the use of
+ // "foo.class = Bar" works in HQL
+ Integer subclassId = new Integer( sc.getSubclassId() );//new Integer(k+1);
+ subclassesByDiscriminatorValue.put( subclassId, sc.getEntityName() );
+ discriminatorValues[k] = subclassId.toString();
+ int id = getTableId(
+ sc.getTable().getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ ),
+ subclassTableNameClosure
+ );
+ notNullColumnTableNumbers[k] = id;
+ notNullColumnNames[k] = subclassTableKeyColumnClosure[id][0]; //( (Column) sc.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
+ }
+ }
+ catch (Exception e) {
+ throw new MappingException("Error parsing discriminator value", e );
+ }
+ k++;
+ }
+
+ initLockers();
+
+ initSubclassPropertyAliasesMap(persistentClass);
+
+ postConstruct(mapping);
+
+ }
+
+ protected boolean isSubclassTableSequentialSelect(int j) {
+ return subclassTableSequentialSelect[j] && !isClassOrSuperclassTable[j];
+ }
+
+
+ /*public void postInstantiate() throws MappingException {
+ super.postInstantiate();
+ //TODO: other lock modes?
+ loader = createEntityLoader(LockMode.NONE, CollectionHelper.EMPTY_MAP);
+ }*/
+
+ public String getSubclassPropertyTableName(int i) {
+ return subclassTableNameClosure[ subclassPropertyTableNumberClosure[i] ];
+ }
+
+ public Type getDiscriminatorType() {
+ return Hibernate.INTEGER;
+ }
+
+ public String getDiscriminatorSQLValue() {
+ return discriminatorSQLString;
+ }
+
+
+ public String getSubclassForDiscriminatorValue(Object value) {
+ return (String) subclassesByDiscriminatorValue.get(value);
+ }
+
+ public Serializable[] getPropertySpaces() {
+ return spaces; // don't need subclass tables, because they can't appear in conditions
+ }
+
+
+ protected String getTableName(int j) {
+ return naturalOrderTableNames[j];
+ }
+
+ protected String[] getKeyColumns(int j) {
+ return naturalOrderTableKeyColumns[j];
+ }
+
+ protected boolean isTableCascadeDeleteEnabled(int j) {
+ return naturalOrderCascadeDeleteEnabled[j];
+ }
+
+ protected boolean isPropertyOfTable(int property, int j) {
+ return naturalOrderPropertyTableNumbers[property]==j;
+ }
+
+ /**
+ * Load an instance using either the <tt>forUpdateLoader</tt> or the outer joining <tt>loader</tt>,
+ * depending upon the value of the <tt>lock</tt> parameter
+ */
+ /*public Object load(Serializable id, Object optionalObject, LockMode lockMode, SessionImplementor session)
+ throws HibernateException {
+
+ if ( log.isTraceEnabled() ) log.trace( "Materializing entity: " + MessageHelper.infoString(this, id) );
+
+ final UniqueEntityLoader loader = hasQueryLoader() ?
+ getQueryLoader() :
+ this.loader;
+ try {
+
+ final Object result = loader.load(id, optionalObject, session);
+
+ if (result!=null) lock(id, getVersion(result), result, lockMode, session);
+
+ return result;
+
+ }
+ catch (SQLException sqle) {
+ throw new JDBCException( "could not load by id: " + MessageHelper.infoString(this, id), sqle );
+ }
+ }*/
+
+ private static final void reverse(Object[] objects, int len) {
+ Object[] temp = new Object[len];
+ for (int i=0; i<len; i++) {
+ temp[i] = objects[len-i-1];
+ }
+ for (int i=0; i<len; i++) {
+ objects[i] = temp[i];
+ }
+ }
+
+
+ /**
+ * Reverse the first n elements of the incoming array
+ * @param objects
+ * @param n
+ * @return New array with the first n elements in reversed order
+ */
+ private static final String[] reverse(String [] objects, int n) {
+
+ int size = objects.length;
+ String[] temp = new String[size];
+
+ for (int i=0; i<n; i++) {
+ temp[i] = objects[n-i-1];
+ }
+
+ for (int i=n; i < size; i++) {
+ temp[i] = objects[i];
+ }
+
+ return temp;
+ }
+
+ /**
+ * Reverse the first n elements of the incoming array
+ * @param objects
+ * @param n
+ * @return New array with the first n elements in reversed order
+ */
+ private static final String[][] reverse(String[][] objects, int n) {
+ int size = objects.length;
+ String[][] temp = new String[size][];
+ for (int i=0; i<n; i++) {
+ temp[i] = objects[n-i-1];
+ }
+
+ for (int i=n; i<size; i++) {
+ temp[i] = objects[i];
+ }
+
+ return temp;
+ }
+
+
+
+ public String fromTableFragment(String alias) {
+ return getTableName() + ' ' + alias;
+ }
+
+ public String getTableName() {
+ return tableNames[0];
+ }
+
+ private static int getTableId(String tableName, String[] tables) {
+ for ( int j=0; j<tables.length; j++ ) {
+ if ( tableName.equals( tables[j] ) ) {
+ return j;
+ }
+ }
+ throw new AssertionFailure("Table " + tableName + " not found");
+ }
+
+ public void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) {
+ if ( hasSubclasses() ) {
+ select.setExtraSelectList( discriminatorFragment(name), getDiscriminatorAlias() );
+ }
+ }
+
+ private CaseFragment discriminatorFragment(String alias) {
+ CaseFragment cases = getFactory().getDialect().createCaseFragment();
+
+ for ( int i=0; i<discriminatorValues.length; i++ ) {
+ cases.addWhenColumnNotNull(
+ generateTableAlias( alias, notNullColumnTableNumbers[i] ),
+ notNullColumnNames[i],
+ discriminatorValues[i]
+ );
+ }
+
+ return cases;
+ }
+
+ public String filterFragment(String alias) {
+ return hasWhere() ?
+ " and " + getSQLWhereString( generateFilterConditionAlias( alias ) ) :
+ "";
+ }
+
+ public String generateFilterConditionAlias(String rootAlias) {
+ return generateTableAlias( rootAlias, tableSpan-1 );
+ }
+
+ public String[] getIdentifierColumnNames() {
+ return tableKeyColumns[0];
+ }
+
+ public String[] getIdentifierColumnReaderTemplates() {
+ return tableKeyColumnReaderTemplates[0];
+ }
+
+ public String[] getIdentifierColumnReaders() {
+ return tableKeyColumnReaders[0];
+ }
+
+ public String[] toColumns(String alias, String propertyName) throws QueryException {
+
+ if ( ENTITY_CLASS.equals(propertyName) ) {
+ // This doesn't actually seem to work but it *might*
+ // work on some dbs. Also it doesn't work if there
+ // are multiple columns of results because it
+ // is not accounting for the suffix:
+ // return new String[] { getDiscriminatorColumnName() };
+
+ return new String[] { discriminatorFragment(alias).toFragmentString() };
+ }
+ else {
+ return super.toColumns(alias, propertyName);
+ }
+
+ }
+
+ protected int[] getPropertyTableNumbersInSelect() {
+ return propertyTableNumbers;
+ }
+
+ protected int getSubclassPropertyTableNumber(int i) {
+ return subclassPropertyTableNumberClosure[i];
+ }
+
+ public int getTableSpan() {
+ return tableSpan;
+ }
+
+ public boolean isMultiTable() {
+ return true;
+ }
+
+ protected int[] getSubclassColumnTableNumberClosure() {
+ return subclassColumnTableNumberClosure;
+ }
+
+ protected int[] getSubclassFormulaTableNumberClosure() {
+ return subclassFormulaTableNumberClosure;
+ }
+
+ protected int[] getPropertyTableNumbers() {
+ return naturalOrderPropertyTableNumbers;
+ }
+
+ protected String[] getSubclassTableKeyColumns(int j) {
+ return subclassTableKeyColumnClosure[j];
+ }
+
+ public String getSubclassTableName(int j) {
+ return subclassTableNameClosure[j];
+ }
+
+ public int getSubclassTableSpan() {
+ return subclassTableNameClosure.length;
+ }
+
+ protected boolean isSubclassTableLazy(int j) {
+ return subclassTableIsLazyClosure[j];
+ }
+
+
+ protected boolean isClassOrSuperclassTable(int j) {
+ return isClassOrSuperclassTable[j];
+ }
+
+ public String getPropertyTableName(String propertyName) {
+ Integer index = getEntityMetamodel().getPropertyIndexOrNull(propertyName);
+ if ( index == null ) {
+ return null;
+ }
+ return tableNames[ propertyTableNumbers[ index.intValue() ] ];
+ }
+
+ public String[] getConstraintOrderedTableNameClosure() {
+ return constraintOrderedTableNames;
+ }
+
+ public String[][] getContraintOrderedTableKeyColumnClosure() {
+ return constraintOrderedKeyColumnNames;
+ }
+
+ public String getRootTableName() {
+ return naturalOrderTableNames[0];
+ }
+
+ public String getRootTableAlias(String drivingAlias) {
+ return generateTableAlias( drivingAlias, getTableId( getRootTableName(), tableNames ) );
+ }
+
+ public Declarer getSubclassPropertyDeclarer(String propertyPath) {
+ if ( "class".equals( propertyPath ) ) {
+ // special case where we need to force incloude all subclass joins
+ return Declarer.SUBCLASS;
+ }
+ return super.getSubclassPropertyDeclarer( propertyPath );
+ }
+}
14 years, 5 months
Hibernate SVN: r19893 - core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined.
by hibernate-commits@lists.jboss.org
Author: sharathjreddy
Date: 2010-07-04 13:35:41 -0400 (Sun, 04 Jul 2010)
New Revision: 19893
Added:
core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Account.java
core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Client.java
core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Person.java
Modified:
core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/JoinedSubclassTest.java
Log:
HHH-4250 : @ManyToOne - @OneToMany doesn't work with @Inheritance(strategy= InheritanceType.JOINED)
Added: core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Account.java
===================================================================
--- core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Account.java (rev 0)
+++ core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Account.java 2010-07-04 17:35:41 UTC (rev 19893)
@@ -0,0 +1,106 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.test.annotations.inheritance.joined;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "ACCOUNT")
+public class Account implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private int id;
+
+ private String number;
+
+ @OneToMany(mappedBy="account")
+ private Set<Client> clients;
+
+ private double balance;
+
+ public Account() {
+ }
+
+ public int getId() {
+ return this.id;
+ }
+
+ @SuppressWarnings("unused")
+ private void setId(int id) {
+ this.id = id;
+ }
+
+ public String getNumber() {
+ return this.number;
+ }
+
+ public void setNumber(String number) {
+ this.number = number;
+ }
+
+ public double getBalance() {
+ return balance;
+ }
+
+ public void setBalance(double balance) {
+ this.balance = balance;
+ }
+
+ public void addClient(Client c) {
+ if (clients == null) {
+ clients = new HashSet<Client>();
+ }
+ clients.add(c);
+ c.setAccount(this);
+ }
+
+
+ public Set<Client> getClients() {
+ return clients;
+ }
+
+ public void setClients(Set<Client> clients) {
+ this.clients = clients;
+ }
+
+
+
+
+
+}
Added: core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Client.java
===================================================================
--- core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Client.java (rev 0)
+++ core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Client.java 2010-07-04 17:35:41 UTC (rev 19893)
@@ -0,0 +1,93 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.test.annotations.inheritance.joined;
+
+import java.io.Serializable;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "CLIENT")
+public class Client extends Person implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private String street;
+
+ private String code;
+
+ private String city;
+
+ @ManyToOne(fetch = FetchType.EAGER)
+ @JoinTable(name = "CLIENT_ACCOUNT",
+ joinColumns = {@JoinColumn(name = "FK_CLIENT", referencedColumnName = "ID")},
+ inverseJoinColumns = {@JoinColumn(name = "FK_ACCOUNT", referencedColumnName = "ID")})
+ private Account account;
+
+
+
+ public Account getAccount() {
+ return account;
+ }
+
+ public void setAccount(Account account) {
+ this.account = account;
+ }
+
+ public Client() {
+ super();
+ }
+
+ public String getStreet() {
+ return street;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+}
Modified: core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/JoinedSubclassTest.java
===================================================================
--- core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/JoinedSubclassTest.java 2010-07-04 17:33:25 UTC (rev 19892)
+++ core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/JoinedSubclassTest.java 2010-07-04 17:35:41 UTC (rev 19893)
@@ -1,7 +1,9 @@
//$Id$
package org.hibernate.test.annotations.inheritance.joined;
+import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
@@ -122,7 +124,49 @@
transaction.commit();
session.close();
}
+
+ //HHH-4250 : @ManyToOne - @OneToMany doesn't work with @Inheritance(strategy= InheritanceType.JOINED)
+ public void testManyToOneWithJoinTable() {
+ Session s = openSession();
+ Transaction tx = s.beginTransaction();
+
+ Client c1 = new Client();
+ c1.setFirstname("Firstname1");
+ c1.setName("Name1");
+ c1.setCode("1234");
+ c1.setStreet("Street1");
+ c1.setCity("City1");
+
+ Account a1 = new Account();
+ a1.setNumber("1000");
+ a1.setBalance(5000.0);
+
+ a1.addClient(c1);
+
+ s.persist(c1);
+ s.persist(a1);
+
+ s.flush();
+ s.clear();
+
+ c1 = (Client) s.load(Client.class, c1.getId());
+ assertEquals(5000.0, c1.getAccount().getBalance());
+
+ s.flush();
+ s.clear();
+
+ a1 = (Account) s.load(Account.class,a1.getId());
+ Set<Client> clients = a1.getClients();
+ assertEquals(1, clients.size());
+ Iterator<Client> it = clients.iterator();
+ c1 = it.next();
+ assertEquals("Name1", c1.getName());
+
+ tx.rollback();
+ s.close();
+ }
+
// public void testManyToOneAndJoin() throws Exception {
// Session session = openSession();
// Transaction transaction = session.beginTransaction();
@@ -168,6 +212,8 @@
Sweater.class,
EventInformation.class,
Alarm.class,
+ Client.class,
+ Account.class
//Asset.class,
//Parent.class,
//PropertyAsset.class,
Added: core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Person.java
===================================================================
--- core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Person.java (rev 0)
+++ core/branches/Branch_3_5/annotations/src/test/java/org/hibernate/test/annotations/inheritance/joined/Person.java 2010-07-04 17:35:41 UTC (rev 19893)
@@ -0,0 +1,80 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. and/or its affiliates 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.test.annotations.inheritance.joined;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.Table;
+
+@Entity
+@Inheritance(strategy = InheritanceType.JOINED)
+@Table(name = "PERSON")
+public class Person {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private int id;
+
+ private String name;
+
+ private String firtsname;
+
+ public Person() {
+
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getFirstname() {
+ return firtsname;
+ }
+
+ public void setFirstname(String firstname) {
+ this.firtsname = firstname;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+}
+
14 years, 5 months
Hibernate SVN: r19892 - core/branches/Branch_3_5/core/src/main/java/org/hibernate/persister/entity.
by hibernate-commits@lists.jboss.org
Author: sharathjreddy
Date: 2010-07-04 13:33:25 -0400 (Sun, 04 Jul 2010)
New Revision: 19892
Modified:
core/branches/Branch_3_5/core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java
Log:
HHH-4250 : @ManyToOne - @OneToMany doesn't work with @Inheritance(strategy= InheritanceType.JOINED)
Modified: core/branches/Branch_3_5/core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java
===================================================================
--- core/branches/Branch_3_5/core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java 2010-07-02 12:57:18 UTC (rev 19891)
+++ core/branches/Branch_3_5/core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java 2010-07-04 17:33:25 UTC (rev 19892)
@@ -1,635 +1,781 @@
-/*
- * Hibernate, Relational Persistence for Idiomatic Java
- *
- * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
- *
- * 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.persister.entity;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import org.hibernate.AssertionFailure;
-import org.hibernate.Hibernate;
-import org.hibernate.HibernateException;
-import org.hibernate.MappingException;
-import org.hibernate.QueryException;
-import org.hibernate.cache.access.EntityRegionAccessStrategy;
-import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
-import org.hibernate.engine.Mapping;
-import org.hibernate.engine.SessionFactoryImplementor;
-import org.hibernate.engine.Versioning;
-import org.hibernate.mapping.Column;
-import org.hibernate.mapping.KeyValue;
-import org.hibernate.mapping.PersistentClass;
-import org.hibernate.mapping.Property;
-import org.hibernate.mapping.Selectable;
-import org.hibernate.mapping.Subclass;
-import org.hibernate.mapping.Table;
-import org.hibernate.sql.CaseFragment;
-import org.hibernate.sql.SelectFragment;
-import org.hibernate.type.AbstractType;
-import org.hibernate.type.Type;
-import org.hibernate.util.ArrayHelper;
-
-/**
- * An <tt>EntityPersister</tt> implementing the normalized "table-per-subclass"
- * mapping strategy
- *
- * @author Gavin King
- */
-public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
-
- // the class hierarchy structure
- private final int tableSpan;
- private final String[] tableNames;
- private final String[] naturalOrderTableNames;
- private final String[][] tableKeyColumns;
- private final String[][] tableKeyColumnReaders;
- private final String[][] tableKeyColumnReaderTemplates;
- private final String[][] naturalOrderTableKeyColumns;
- private final String[][] naturalOrderTableKeyColumnReaders;
- private final String[][] naturalOrderTableKeyColumnReaderTemplates;
- private final boolean[] naturalOrderCascadeDeleteEnabled;
-
- private final String[] spaces;
-
- private final String[] subclassClosure;
-
- private final String[] subclassTableNameClosure;
- private final String[][] subclassTableKeyColumnClosure;
- private final boolean[] isClassOrSuperclassTable;
-
- // properties of this class, including inherited properties
- private final int[] naturalOrderPropertyTableNumbers;
- private final int[] propertyTableNumbers;
-
- // the closure of all properties in the entire hierarchy including
- // subclasses and superclasses of this class
- private final int[] subclassPropertyTableNumberClosure;
-
- // the closure of all columns used by the entire hierarchy including
- // subclasses and superclasses of this class
- private final int[] subclassColumnTableNumberClosure;
- private final int[] subclassFormulaTableNumberClosure;
-
- // subclass discrimination works by assigning particular
- // values to certain combinations of null primary key
- // values in the outer join using an SQL CASE
- private final Map subclassesByDiscriminatorValue = new HashMap();
- private final String[] discriminatorValues;
- private final String[] notNullColumnNames;
- private final int[] notNullColumnTableNumbers;
-
- private final String[] constraintOrderedTableNames;
- private final String[][] constraintOrderedKeyColumnNames;
-
- private final String discriminatorSQLString;
-
- //INITIALIZATION:
-
- public JoinedSubclassEntityPersister(
- final PersistentClass persistentClass,
- final EntityRegionAccessStrategy cacheAccessStrategy,
- final SessionFactoryImplementor factory,
- final Mapping mapping) throws HibernateException {
-
- super( persistentClass, cacheAccessStrategy, factory );
-
- // DISCRIMINATOR
-
- final Object discriminatorValue;
- if ( persistentClass.isPolymorphic() ) {
- try {
- discriminatorValue = new Integer( persistentClass.getSubclassId() );
- discriminatorSQLString = discriminatorValue.toString();
- }
- catch (Exception e) {
- throw new MappingException("Could not format discriminator value to SQL string", e );
- }
- }
- else {
- discriminatorValue = null;
- discriminatorSQLString = null;
- }
-
- if ( optimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION ) {
- throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" );
- }
-
- //MULTITABLES
-
- final int idColumnSpan = getIdentifierColumnSpan();
-
- ArrayList tables = new ArrayList();
- ArrayList keyColumns = new ArrayList();
- ArrayList keyColumnReaders = new ArrayList();
- ArrayList keyColumnReaderTemplates = new ArrayList();
- ArrayList cascadeDeletes = new ArrayList();
- Iterator titer = persistentClass.getTableClosureIterator();
- Iterator kiter = persistentClass.getKeyClosureIterator();
- while ( titer.hasNext() ) {
- Table tab = (Table) titer.next();
- KeyValue key = (KeyValue) kiter.next();
- String tabname = tab.getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
- );
- tables.add(tabname);
- String[] keyCols = new String[idColumnSpan];
- String[] keyColReaders = new String[idColumnSpan];
- String[] keyColReaderTemplates = new String[idColumnSpan];
- Iterator citer = key.getColumnIterator();
- for ( int k=0; k<idColumnSpan; k++ ) {
- Column column = (Column) citer.next();
- keyCols[k] = column.getQuotedName( factory.getDialect() );
- keyColReaders[k] = column.getReadExpr( factory.getDialect() );
- keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
- }
- keyColumns.add(keyCols);
- keyColumnReaders.add(keyColReaders);
- keyColumnReaderTemplates.add(keyColReaderTemplates);
- cascadeDeletes.add( new Boolean( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ) );
- }
- naturalOrderTableNames = ArrayHelper.toStringArray(tables);
- naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray(keyColumns);
- naturalOrderTableKeyColumnReaders = ArrayHelper.to2DStringArray(keyColumnReaders);
- naturalOrderTableKeyColumnReaderTemplates = ArrayHelper.to2DStringArray(keyColumnReaderTemplates);
- naturalOrderCascadeDeleteEnabled = ArrayHelper.toBooleanArray(cascadeDeletes);
-
- ArrayList subtables = new ArrayList();
- ArrayList isConcretes = new ArrayList();
- keyColumns = new ArrayList();
- titer = persistentClass.getSubclassTableClosureIterator();
- while ( titer.hasNext() ) {
- Table tab = (Table) titer.next();
- isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassTable(tab) ) );
- String tabname = tab.getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
- );
- subtables.add(tabname);
- String[] key = new String[idColumnSpan];
- Iterator citer = tab.getPrimaryKey().getColumnIterator();
- for ( int k=0; k<idColumnSpan; k++ ) {
- key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
- }
- keyColumns.add(key);
- }
- subclassTableNameClosure = ArrayHelper.toStringArray(subtables);
- subclassTableKeyColumnClosure = ArrayHelper.to2DStringArray(keyColumns);
- isClassOrSuperclassTable = ArrayHelper.toBooleanArray(isConcretes);
-
- constraintOrderedTableNames = new String[subclassTableNameClosure.length];
- constraintOrderedKeyColumnNames = new String[subclassTableNameClosure.length][];
- int currentPosition = 0;
- for ( int i = subclassTableNameClosure.length - 1; i >= 0 ; i--, currentPosition++ ) {
- constraintOrderedTableNames[currentPosition] = subclassTableNameClosure[i];
- constraintOrderedKeyColumnNames[currentPosition] = subclassTableKeyColumnClosure[i];
- }
-
- tableSpan = naturalOrderTableNames.length;
- tableNames = reverse(naturalOrderTableNames);
- tableKeyColumns = reverse(naturalOrderTableKeyColumns);
- tableKeyColumnReaders = reverse(naturalOrderTableKeyColumnReaders);
- tableKeyColumnReaderTemplates = reverse(naturalOrderTableKeyColumnReaderTemplates);
- reverse(subclassTableNameClosure, tableSpan);
- reverse(subclassTableKeyColumnClosure, tableSpan);
-
- spaces = ArrayHelper.join(
- tableNames,
- ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
- );
-
- // Custom sql
- customSQLInsert = new String[tableSpan];
- customSQLUpdate = new String[tableSpan];
- customSQLDelete = new String[tableSpan];
- insertCallable = new boolean[tableSpan];
- updateCallable = new boolean[tableSpan];
- deleteCallable = new boolean[tableSpan];
- insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
- updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
- deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
-
- PersistentClass pc = persistentClass;
- int jk = tableSpan-1;
- while (pc!=null) {
- customSQLInsert[jk] = pc.getCustomSQLInsert();
- insertCallable[jk] = customSQLInsert[jk] != null && pc.isCustomInsertCallable();
- insertResultCheckStyles[jk] = pc.getCustomSQLInsertCheckStyle() == null
- ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[jk], insertCallable[jk] )
- : pc.getCustomSQLInsertCheckStyle();
- customSQLUpdate[jk] = pc.getCustomSQLUpdate();
- updateCallable[jk] = customSQLUpdate[jk] != null && pc.isCustomUpdateCallable();
- updateResultCheckStyles[jk] = pc.getCustomSQLUpdateCheckStyle() == null
- ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[jk], updateCallable[jk] )
- : pc.getCustomSQLUpdateCheckStyle();
- customSQLDelete[jk] = pc.getCustomSQLDelete();
- deleteCallable[jk] = customSQLDelete[jk] != null && pc.isCustomDeleteCallable();
- deleteResultCheckStyles[jk] = pc.getCustomSQLDeleteCheckStyle() == null
- ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[jk], deleteCallable[jk] )
- : pc.getCustomSQLDeleteCheckStyle();
- jk--;
- pc = pc.getSuperclass();
- }
- if ( jk != -1 ) {
- throw new AssertionFailure( "Tablespan does not match height of joined-subclass hiearchy." );
- }
-
- // PROPERTIES
-
- int hydrateSpan = getPropertySpan();
- naturalOrderPropertyTableNumbers = new int[hydrateSpan];
- propertyTableNumbers = new int[hydrateSpan];
- Iterator iter = persistentClass.getPropertyClosureIterator();
- int i=0;
- while( iter.hasNext() ) {
- Property prop = (Property) iter.next();
- String tabname = prop.getValue().getTable().getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
- );
- propertyTableNumbers[i] = getTableId(tabname, tableNames);
- naturalOrderPropertyTableNumbers[i] = getTableId(tabname, naturalOrderTableNames);
- i++;
- }
-
- // subclass closure properties
-
- //TODO: code duplication with SingleTableEntityPersister
-
- ArrayList columnTableNumbers = new ArrayList();
- ArrayList formulaTableNumbers = new ArrayList();
- ArrayList propTableNumbers = new ArrayList();
-
- iter = persistentClass.getSubclassPropertyClosureIterator();
- while ( iter.hasNext() ) {
- Property prop = (Property) iter.next();
- Table tab = prop.getValue().getTable();
- String tabname = tab.getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
- );
- Integer tabnum = new Integer( getTableId(tabname, subclassTableNameClosure) );
- propTableNumbers.add(tabnum);
-
- Iterator citer = prop.getColumnIterator();
- while ( citer.hasNext() ) {
- Selectable thing = (Selectable) citer.next();
- if ( thing.isFormula() ) {
- formulaTableNumbers.add(tabnum);
- }
- else {
- columnTableNumbers.add(tabnum);
- }
- }
-
- }
-
- subclassColumnTableNumberClosure = ArrayHelper.toIntArray(columnTableNumbers);
- subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propTableNumbers);
- subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaTableNumbers);
-
- // SUBCLASSES
-
- int subclassSpan = persistentClass.getSubclassSpan() + 1;
- subclassClosure = new String[subclassSpan];
- subclassClosure[subclassSpan-1] = getEntityName();
- if ( persistentClass.isPolymorphic() ) {
- subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
- discriminatorValues = new String[subclassSpan];
- discriminatorValues[subclassSpan-1] = discriminatorSQLString;
- notNullColumnTableNumbers = new int[subclassSpan];
- final int id = getTableId(
- persistentClass.getTable().getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
- ),
- subclassTableNameClosure
- );
- notNullColumnTableNumbers[subclassSpan-1] = id;
- notNullColumnNames = new String[subclassSpan];
- notNullColumnNames[subclassSpan-1] = subclassTableKeyColumnClosure[id][0]; //( (Column) model.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
- }
- else {
- discriminatorValues = null;
- notNullColumnTableNumbers = null;
- notNullColumnNames = null;
- }
-
- iter = persistentClass.getSubclassIterator();
- int k=0;
- while ( iter.hasNext() ) {
- Subclass sc = (Subclass) iter.next();
- subclassClosure[k] = sc.getEntityName();
- try {
- if ( persistentClass.isPolymorphic() ) {
- // we now use subclass ids that are consistent across all
- // persisters for a class hierarchy, so that the use of
- // "foo.class = Bar" works in HQL
- Integer subclassId = new Integer( sc.getSubclassId() );//new Integer(k+1);
- subclassesByDiscriminatorValue.put( subclassId, sc.getEntityName() );
- discriminatorValues[k] = subclassId.toString();
- int id = getTableId(
- sc.getTable().getQualifiedName(
- factory.getDialect(),
- factory.getSettings().getDefaultCatalogName(),
- factory.getSettings().getDefaultSchemaName()
- ),
- subclassTableNameClosure
- );
- notNullColumnTableNumbers[k] = id;
- notNullColumnNames[k] = subclassTableKeyColumnClosure[id][0]; //( (Column) sc.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
- }
- }
- catch (Exception e) {
- throw new MappingException("Error parsing discriminator value", e );
- }
- k++;
- }
-
- initLockers();
-
- initSubclassPropertyAliasesMap(persistentClass);
-
- postConstruct(mapping);
-
- }
-
- /*public void postInstantiate() throws MappingException {
- super.postInstantiate();
- //TODO: other lock modes?
- loader = createEntityLoader(LockMode.NONE, CollectionHelper.EMPTY_MAP);
- }*/
-
- public String getSubclassPropertyTableName(int i) {
- return subclassTableNameClosure[ subclassPropertyTableNumberClosure[i] ];
- }
-
- public Type getDiscriminatorType() {
- return Hibernate.INTEGER;
- }
-
- public String getDiscriminatorSQLValue() {
- return discriminatorSQLString;
- }
-
-
- public String getSubclassForDiscriminatorValue(Object value) {
- return (String) subclassesByDiscriminatorValue.get(value);
- }
-
- public Serializable[] getPropertySpaces() {
- return spaces; // don't need subclass tables, because they can't appear in conditions
- }
-
-
- protected String getTableName(int j) {
- return naturalOrderTableNames[j];
- }
-
- protected String[] getKeyColumns(int j) {
- return naturalOrderTableKeyColumns[j];
- }
-
- protected boolean isTableCascadeDeleteEnabled(int j) {
- return naturalOrderCascadeDeleteEnabled[j];
- }
-
- protected boolean isPropertyOfTable(int property, int j) {
- return naturalOrderPropertyTableNumbers[property]==j;
- }
-
- /**
- * Load an instance using either the <tt>forUpdateLoader</tt> or the outer joining <tt>loader</tt>,
- * depending upon the value of the <tt>lock</tt> parameter
- */
- /*public Object load(Serializable id, Object optionalObject, LockMode lockMode, SessionImplementor session)
- throws HibernateException {
-
- if ( log.isTraceEnabled() ) log.trace( "Materializing entity: " + MessageHelper.infoString(this, id) );
-
- final UniqueEntityLoader loader = hasQueryLoader() ?
- getQueryLoader() :
- this.loader;
- try {
-
- final Object result = loader.load(id, optionalObject, session);
-
- if (result!=null) lock(id, getVersion(result), result, lockMode, session);
-
- return result;
-
- }
- catch (SQLException sqle) {
- throw new JDBCException( "could not load by id: " + MessageHelper.infoString(this, id), sqle );
- }
- }*/
-
- private static final void reverse(Object[] objects, int len) {
- Object[] temp = new Object[len];
- for (int i=0; i<len; i++) {
- temp[i] = objects[len-i-1];
- }
- for (int i=0; i<len; i++) {
- objects[i] = temp[i];
- }
- }
-
- private static final String[] reverse(String[] objects) {
- int len = objects.length;
- String[] temp = new String[len];
- for (int i=0; i<len; i++) {
- temp[i] = objects[len-i-1];
- }
- return temp;
- }
-
- private static final String[][] reverse(String[][] objects) {
- int len = objects.length;
- String[][] temp = new String[len][];
- for (int i=0; i<len; i++) {
- temp[i] = objects[len-i-1];
- }
- return temp;
- }
-
- public String fromTableFragment(String alias) {
- return getTableName() + ' ' + alias;
- }
-
- public String getTableName() {
- return tableNames[0];
- }
-
- private static int getTableId(String tableName, String[] tables) {
- for ( int j=0; j<tables.length; j++ ) {
- if ( tableName.equals( tables[j] ) ) {
- return j;
- }
- }
- throw new AssertionFailure("Table " + tableName + " not found");
- }
-
- public void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) {
- if ( hasSubclasses() ) {
- select.setExtraSelectList( discriminatorFragment(name), getDiscriminatorAlias() );
- }
- }
-
- private CaseFragment discriminatorFragment(String alias) {
- CaseFragment cases = getFactory().getDialect().createCaseFragment();
-
- for ( int i=0; i<discriminatorValues.length; i++ ) {
- cases.addWhenColumnNotNull(
- generateTableAlias( alias, notNullColumnTableNumbers[i] ),
- notNullColumnNames[i],
- discriminatorValues[i]
- );
- }
-
- return cases;
- }
-
- public String filterFragment(String alias) {
- return hasWhere() ?
- " and " + getSQLWhereString( generateFilterConditionAlias( alias ) ) :
- "";
- }
-
- public String generateFilterConditionAlias(String rootAlias) {
- return generateTableAlias( rootAlias, tableSpan-1 );
- }
-
- public String[] getIdentifierColumnNames() {
- return tableKeyColumns[0];
- }
-
- public String[] getIdentifierColumnReaderTemplates() {
- return tableKeyColumnReaderTemplates[0];
- }
-
- public String[] getIdentifierColumnReaders() {
- return tableKeyColumnReaders[0];
- }
-
- public String[] toColumns(String alias, String propertyName) throws QueryException {
-
- if ( ENTITY_CLASS.equals(propertyName) ) {
- // This doesn't actually seem to work but it *might*
- // work on some dbs. Also it doesn't work if there
- // are multiple columns of results because it
- // is not accounting for the suffix:
- // return new String[] { getDiscriminatorColumnName() };
-
- return new String[] { discriminatorFragment(alias).toFragmentString() };
- }
- else {
- return super.toColumns(alias, propertyName);
- }
-
- }
-
- protected int[] getPropertyTableNumbersInSelect() {
- return propertyTableNumbers;
- }
-
- protected int getSubclassPropertyTableNumber(int i) {
- return subclassPropertyTableNumberClosure[i];
- }
-
- public int getTableSpan() {
- return tableSpan;
- }
-
- public boolean isMultiTable() {
- return true;
- }
-
- protected int[] getSubclassColumnTableNumberClosure() {
- return subclassColumnTableNumberClosure;
- }
-
- protected int[] getSubclassFormulaTableNumberClosure() {
- return subclassFormulaTableNumberClosure;
- }
-
- protected int[] getPropertyTableNumbers() {
- return naturalOrderPropertyTableNumbers;
- }
-
- protected String[] getSubclassTableKeyColumns(int j) {
- return subclassTableKeyColumnClosure[j];
- }
-
- public String getSubclassTableName(int j) {
- return subclassTableNameClosure[j];
- }
-
- public int getSubclassTableSpan() {
- return subclassTableNameClosure.length;
- }
-
- protected boolean isClassOrSuperclassTable(int j) {
- return isClassOrSuperclassTable[j];
- }
-
- public String getPropertyTableName(String propertyName) {
- Integer index = getEntityMetamodel().getPropertyIndexOrNull(propertyName);
- if ( index == null ) {
- return null;
- }
- return tableNames[ propertyTableNumbers[ index.intValue() ] ];
- }
-
- public String[] getConstraintOrderedTableNameClosure() {
- return constraintOrderedTableNames;
- }
-
- public String[][] getContraintOrderedTableKeyColumnClosure() {
- return constraintOrderedKeyColumnNames;
- }
-
- public String getRootTableName() {
- return naturalOrderTableNames[0];
- }
-
- public String getRootTableAlias(String drivingAlias) {
- return generateTableAlias( drivingAlias, getTableId( getRootTableName(), tableNames ) );
- }
-
- public Declarer getSubclassPropertyDeclarer(String propertyPath) {
- if ( "class".equals( propertyPath ) ) {
- // special case where we need to force incloude all subclass joins
- return Declarer.SUBCLASS;
- }
- return super.getSubclassPropertyDeclarer( propertyPath );
- }
-}
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ *
+ * 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.persister.entity;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.hibernate.AssertionFailure;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.QueryException;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.engine.Versioning;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Join;
+import org.hibernate.mapping.KeyValue;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.Selectable;
+import org.hibernate.mapping.Subclass;
+import org.hibernate.mapping.Table;
+import org.hibernate.sql.CaseFragment;
+import org.hibernate.sql.SelectFragment;
+import org.hibernate.type.AbstractType;
+import org.hibernate.type.Type;
+import org.hibernate.util.ArrayHelper;
+
+/**
+ * An <tt>EntityPersister</tt> implementing the normalized "table-per-subclass"
+ * mapping strategy
+ *
+ * @author Gavin King
+ */
+public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
+
+ // the class hierarchy structure
+ private final int tableSpan;
+ private final String[] tableNames;
+ private final String[] naturalOrderTableNames;
+ private final String[][] tableKeyColumns;
+ private final String[][] tableKeyColumnReaders;
+ private final String[][] tableKeyColumnReaderTemplates;
+ private final String[][] naturalOrderTableKeyColumns;
+ private final String[][] naturalOrderTableKeyColumnReaders;
+ private final String[][] naturalOrderTableKeyColumnReaderTemplates;
+ private final boolean[] naturalOrderCascadeDeleteEnabled;
+
+ private final String[] spaces;
+
+ private final String[] subclassClosure;
+
+ private final String[] subclassTableNameClosure;
+ private final String[][] subclassTableKeyColumnClosure;
+ private final boolean[] isClassOrSuperclassTable;
+
+ // properties of this class, including inherited properties
+ private final int[] naturalOrderPropertyTableNumbers;
+ private final int[] propertyTableNumbers;
+
+ // the closure of all properties in the entire hierarchy including
+ // subclasses and superclasses of this class
+ private final int[] subclassPropertyTableNumberClosure;
+
+ // the closure of all columns used by the entire hierarchy including
+ // subclasses and superclasses of this class
+ private final int[] subclassColumnTableNumberClosure;
+ private final int[] subclassFormulaTableNumberClosure;
+
+ private final boolean[] subclassTableSequentialSelect;
+ private final boolean[] subclassTableIsLazyClosure;
+
+ // subclass discrimination works by assigning particular
+ // values to certain combinations of null primary key
+ // values in the outer join using an SQL CASE
+ private final Map subclassesByDiscriminatorValue = new HashMap();
+ private final String[] discriminatorValues;
+ private final String[] notNullColumnNames;
+ private final int[] notNullColumnTableNumbers;
+
+ private final String[] constraintOrderedTableNames;
+ private final String[][] constraintOrderedKeyColumnNames;
+
+ private final String discriminatorSQLString;
+
+ //INITIALIZATION:
+
+ public JoinedSubclassEntityPersister(
+ final PersistentClass persistentClass,
+ final EntityRegionAccessStrategy cacheAccessStrategy,
+ final SessionFactoryImplementor factory,
+ final Mapping mapping) throws HibernateException {
+
+ super( persistentClass, cacheAccessStrategy, factory );
+
+ // DISCRIMINATOR
+
+ final Object discriminatorValue;
+ if ( persistentClass.isPolymorphic() ) {
+ try {
+ discriminatorValue = new Integer( persistentClass.getSubclassId() );
+ discriminatorSQLString = discriminatorValue.toString();
+ }
+ catch (Exception e) {
+ throw new MappingException("Could not format discriminator value to SQL string", e );
+ }
+ }
+ else {
+ discriminatorValue = null;
+ discriminatorSQLString = null;
+ }
+
+ if ( optimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION ) {
+ throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" );
+ }
+
+ //MULTITABLES
+
+ final int idColumnSpan = getIdentifierColumnSpan();
+
+ ArrayList tables = new ArrayList();
+ ArrayList keyColumns = new ArrayList();
+ ArrayList keyColumnReaders = new ArrayList();
+ ArrayList keyColumnReaderTemplates = new ArrayList();
+ ArrayList cascadeDeletes = new ArrayList();
+ Iterator titer = persistentClass.getTableClosureIterator();
+ Iterator kiter = persistentClass.getKeyClosureIterator();
+ while ( titer.hasNext() ) {
+ Table tab = (Table) titer.next();
+ KeyValue key = (KeyValue) kiter.next();
+ String tabname = tab.getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ );
+ tables.add(tabname);
+ String[] keyCols = new String[idColumnSpan];
+ String[] keyColReaders = new String[idColumnSpan];
+ String[] keyColReaderTemplates = new String[idColumnSpan];
+ Iterator citer = key.getColumnIterator();
+ for ( int k=0; k<idColumnSpan; k++ ) {
+ Column column = (Column) citer.next();
+ keyCols[k] = column.getQuotedName( factory.getDialect() );
+ keyColReaders[k] = column.getReadExpr( factory.getDialect() );
+ keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
+ }
+ keyColumns.add(keyCols);
+ keyColumnReaders.add(keyColReaders);
+ keyColumnReaderTemplates.add(keyColReaderTemplates);
+ cascadeDeletes.add( new Boolean( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ) );
+ }
+
+ //Span of the tables directly mapped by this entity and super-classes, if any
+ int coreTableSpan = tables.size();
+
+ Iterator joinIter = persistentClass.getJoinClosureIterator();
+ while ( joinIter.hasNext() ) {
+ Join join = (Join) joinIter.next();
+
+ Table tab = join.getTable();
+
+ String tabname = tab.getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ );
+ tables.add(tabname);
+
+ KeyValue key = join.getKey();
+ int joinIdColumnSpan = key.getColumnSpan();
+
+ String[] keyCols = new String[joinIdColumnSpan];
+ String[] keyColReaders = new String[joinIdColumnSpan];
+ String[] keyColReaderTemplates = new String[joinIdColumnSpan];
+
+ Iterator citer = key.getColumnIterator();
+
+ for ( int k=0; k<joinIdColumnSpan; k++ ) {
+ Column column = (Column) citer.next();
+ keyCols[k] = column.getQuotedName( factory.getDialect() );
+ keyColReaders[k] = column.getReadExpr( factory.getDialect() );
+ keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
+ }
+ keyColumns.add(keyCols);
+ keyColumnReaders.add(keyColReaders);
+ keyColumnReaderTemplates.add(keyColReaderTemplates);
+ cascadeDeletes.add( new Boolean( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ) );
+ }
+
+ naturalOrderTableNames = ArrayHelper.toStringArray(tables);
+ naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray(keyColumns);
+ naturalOrderTableKeyColumnReaders = ArrayHelper.to2DStringArray(keyColumnReaders);
+ naturalOrderTableKeyColumnReaderTemplates = ArrayHelper.to2DStringArray(keyColumnReaderTemplates);
+ naturalOrderCascadeDeleteEnabled = ArrayHelper.toBooleanArray(cascadeDeletes);
+
+ ArrayList subtables = new ArrayList();
+ ArrayList isConcretes = new ArrayList();
+ ArrayList isDeferreds = new ArrayList();
+ ArrayList isLazies = new ArrayList();
+
+ keyColumns = new ArrayList();
+ titer = persistentClass.getSubclassTableClosureIterator();
+ while ( titer.hasNext() ) {
+ Table tab = (Table) titer.next();
+ isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassTable(tab) ) );
+ isDeferreds.add(Boolean.FALSE);
+ isLazies.add(Boolean.FALSE);
+ String tabname = tab.getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ );
+ subtables.add(tabname);
+ String[] key = new String[idColumnSpan];
+ Iterator citer = tab.getPrimaryKey().getColumnIterator();
+ for ( int k=0; k<idColumnSpan; k++ ) {
+ key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
+ }
+ keyColumns.add(key);
+ }
+
+ //Add joins
+ joinIter = persistentClass.getSubclassJoinClosureIterator();
+ while ( joinIter.hasNext() ) {
+ Join join = (Join) joinIter.next();
+
+ Table tab = join.getTable();
+
+ isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassTable(tab) ) );
+ isDeferreds.add( new Boolean( join.isSequentialSelect() ) );
+ isLazies.add(new Boolean(join.isLazy()));
+
+ String tabname = tab.getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ );
+ subtables.add(tabname);
+ String[] key = new String[idColumnSpan];
+ Iterator citer = tab.getPrimaryKey().getColumnIterator();
+ for ( int k=0; k<idColumnSpan; k++ ) {
+ key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
+ }
+ keyColumns.add(key);
+
+ }
+
+ String [] naturalOrderSubclassTableNameClosure = ArrayHelper.toStringArray(subtables);
+ String[][] naturalOrderSubclassTableKeyColumnClosure = ArrayHelper.to2DStringArray(keyColumns);
+ isClassOrSuperclassTable = ArrayHelper.toBooleanArray(isConcretes);
+ subclassTableSequentialSelect = ArrayHelper.toBooleanArray(isDeferreds);
+ subclassTableIsLazyClosure = ArrayHelper.toBooleanArray(isLazies);
+
+ constraintOrderedTableNames = new String[naturalOrderSubclassTableNameClosure.length];
+ constraintOrderedKeyColumnNames = new String[naturalOrderSubclassTableNameClosure.length][];
+ int currentPosition = 0;
+ for ( int i = naturalOrderSubclassTableNameClosure.length - 1; i >= 0 ; i--, currentPosition++ ) {
+ constraintOrderedTableNames[currentPosition] = naturalOrderSubclassTableNameClosure[i];
+ constraintOrderedKeyColumnNames[currentPosition] = naturalOrderSubclassTableKeyColumnClosure[i];
+ }
+
+ /**
+ * Suppose an entity Client extends Person, mapped to the tables CLIENT and PERSON respectively.
+ * For the Client entity:
+ * naturalOrderTableNames -> PERSON, CLIENT; this reflects the sequence in which the tables are
+ * added to the meta-data when the annotated entities are processed.
+ * However, in some instances, for example when generating joins, the CLIENT table needs to be
+ * the first table as it will the driving table.
+ * tableNames -> CLIENT, PERSON
+ */
+
+ tableSpan = naturalOrderTableNames.length;
+ tableNames = reverse(naturalOrderTableNames, coreTableSpan);
+ tableKeyColumns = reverse(naturalOrderTableKeyColumns, coreTableSpan);
+ tableKeyColumnReaders = reverse(naturalOrderTableKeyColumnReaders, coreTableSpan);
+ tableKeyColumnReaderTemplates = reverse(naturalOrderTableKeyColumnReaderTemplates, coreTableSpan);
+ subclassTableNameClosure = reverse(naturalOrderSubclassTableNameClosure, coreTableSpan);
+ subclassTableKeyColumnClosure = reverse(naturalOrderSubclassTableKeyColumnClosure, coreTableSpan);
+
+ spaces = ArrayHelper.join(
+ tableNames,
+ ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
+ );
+
+ // Custom sql
+ customSQLInsert = new String[tableSpan];
+ customSQLUpdate = new String[tableSpan];
+ customSQLDelete = new String[tableSpan];
+ insertCallable = new boolean[tableSpan];
+ updateCallable = new boolean[tableSpan];
+ deleteCallable = new boolean[tableSpan];
+ insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
+ updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
+ deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
+
+ PersistentClass pc = persistentClass;
+ int jk = coreTableSpan-1;
+ while (pc!=null) {
+ customSQLInsert[jk] = pc.getCustomSQLInsert();
+ insertCallable[jk] = customSQLInsert[jk] != null && pc.isCustomInsertCallable();
+ insertResultCheckStyles[jk] = pc.getCustomSQLInsertCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[jk], insertCallable[jk] )
+ : pc.getCustomSQLInsertCheckStyle();
+ customSQLUpdate[jk] = pc.getCustomSQLUpdate();
+ updateCallable[jk] = customSQLUpdate[jk] != null && pc.isCustomUpdateCallable();
+ updateResultCheckStyles[jk] = pc.getCustomSQLUpdateCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[jk], updateCallable[jk] )
+ : pc.getCustomSQLUpdateCheckStyle();
+ customSQLDelete[jk] = pc.getCustomSQLDelete();
+ deleteCallable[jk] = customSQLDelete[jk] != null && pc.isCustomDeleteCallable();
+ deleteResultCheckStyles[jk] = pc.getCustomSQLDeleteCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[jk], deleteCallable[jk] )
+ : pc.getCustomSQLDeleteCheckStyle();
+ jk--;
+ pc = pc.getSuperclass();
+ }
+
+ if ( jk != -1 ) {
+ throw new AssertionFailure( "Tablespan does not match height of joined-subclass hiearchy." );
+ }
+
+ joinIter = persistentClass.getJoinClosureIterator();
+ int j = coreTableSpan;
+ while ( joinIter.hasNext() ) {
+ Join join = (Join) joinIter.next();
+
+ customSQLInsert[j] = join.getCustomSQLInsert();
+ insertCallable[j] = customSQLInsert[j] != null && join.isCustomInsertCallable();
+ insertResultCheckStyles[j] = join.getCustomSQLInsertCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[j], insertCallable[j] )
+ : join.getCustomSQLInsertCheckStyle();
+ customSQLUpdate[j] = join.getCustomSQLUpdate();
+ updateCallable[j] = customSQLUpdate[j] != null && join.isCustomUpdateCallable();
+ updateResultCheckStyles[j] = join.getCustomSQLUpdateCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[j], updateCallable[j] )
+ : join.getCustomSQLUpdateCheckStyle();
+ customSQLDelete[j] = join.getCustomSQLDelete();
+ deleteCallable[j] = customSQLDelete[j] != null && join.isCustomDeleteCallable();
+ deleteResultCheckStyles[j] = join.getCustomSQLDeleteCheckStyle() == null
+ ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[j], deleteCallable[j] )
+ : join.getCustomSQLDeleteCheckStyle();
+ j++;
+ }
+
+ // PROPERTIES
+ int hydrateSpan = getPropertySpan();
+ naturalOrderPropertyTableNumbers = new int[hydrateSpan];
+ propertyTableNumbers = new int[hydrateSpan];
+ Iterator iter = persistentClass.getPropertyClosureIterator();
+ int i=0;
+ while( iter.hasNext() ) {
+ Property prop = (Property) iter.next();
+ String tabname = prop.getValue().getTable().getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ );
+ propertyTableNumbers[i] = getTableId(tabname, tableNames);
+ naturalOrderPropertyTableNumbers[i] = getTableId(tabname, naturalOrderTableNames);
+ i++;
+ }
+
+ // subclass closure properties
+
+ //TODO: code duplication with SingleTableEntityPersister
+
+ ArrayList columnTableNumbers = new ArrayList();
+ ArrayList formulaTableNumbers = new ArrayList();
+ ArrayList propTableNumbers = new ArrayList();
+
+ iter = persistentClass.getSubclassPropertyClosureIterator();
+ while ( iter.hasNext() ) {
+ Property prop = (Property) iter.next();
+ Table tab = prop.getValue().getTable();
+ String tabname = tab.getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ );
+ Integer tabnum = new Integer( getTableId(tabname, subclassTableNameClosure) );
+ propTableNumbers.add(tabnum);
+
+ Iterator citer = prop.getColumnIterator();
+ while ( citer.hasNext() ) {
+ Selectable thing = (Selectable) citer.next();
+ if ( thing.isFormula() ) {
+ formulaTableNumbers.add(tabnum);
+ }
+ else {
+ columnTableNumbers.add(tabnum);
+ }
+ }
+
+ }
+
+ subclassColumnTableNumberClosure = ArrayHelper.toIntArray(columnTableNumbers);
+ subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propTableNumbers);
+ subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaTableNumbers);
+
+ // SUBCLASSES
+
+ int subclassSpan = persistentClass.getSubclassSpan() + 1;
+ subclassClosure = new String[subclassSpan];
+ subclassClosure[subclassSpan-1] = getEntityName();
+ if ( persistentClass.isPolymorphic() ) {
+ subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
+ discriminatorValues = new String[subclassSpan];
+ discriminatorValues[subclassSpan-1] = discriminatorSQLString;
+ notNullColumnTableNumbers = new int[subclassSpan];
+ final int id = getTableId(
+ persistentClass.getTable().getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ ),
+ subclassTableNameClosure
+ );
+ notNullColumnTableNumbers[subclassSpan-1] = id;
+ notNullColumnNames = new String[subclassSpan];
+ notNullColumnNames[subclassSpan-1] = subclassTableKeyColumnClosure[id][0]; //( (Column) model.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
+ }
+ else {
+ discriminatorValues = null;
+ notNullColumnTableNumbers = null;
+ notNullColumnNames = null;
+ }
+
+ iter = persistentClass.getSubclassIterator();
+ int k=0;
+ while ( iter.hasNext() ) {
+ Subclass sc = (Subclass) iter.next();
+ subclassClosure[k] = sc.getEntityName();
+ try {
+ if ( persistentClass.isPolymorphic() ) {
+ // we now use subclass ids that are consistent across all
+ // persisters for a class hierarchy, so that the use of
+ // "foo.class = Bar" works in HQL
+ Integer subclassId = new Integer( sc.getSubclassId() );//new Integer(k+1);
+ subclassesByDiscriminatorValue.put( subclassId, sc.getEntityName() );
+ discriminatorValues[k] = subclassId.toString();
+ int id = getTableId(
+ sc.getTable().getQualifiedName(
+ factory.getDialect(),
+ factory.getSettings().getDefaultCatalogName(),
+ factory.getSettings().getDefaultSchemaName()
+ ),
+ subclassTableNameClosure
+ );
+ notNullColumnTableNumbers[k] = id;
+ notNullColumnNames[k] = subclassTableKeyColumnClosure[id][0]; //( (Column) sc.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
+ }
+ }
+ catch (Exception e) {
+ throw new MappingException("Error parsing discriminator value", e );
+ }
+ k++;
+ }
+
+ initLockers();
+
+ initSubclassPropertyAliasesMap(persistentClass);
+
+ postConstruct(mapping);
+
+ }
+
+ protected boolean isSubclassTableSequentialSelect(int j) {
+ return subclassTableSequentialSelect[j] && !isClassOrSuperclassTable[j];
+ }
+
+
+ /*public void postInstantiate() throws MappingException {
+ super.postInstantiate();
+ //TODO: other lock modes?
+ loader = createEntityLoader(LockMode.NONE, CollectionHelper.EMPTY_MAP);
+ }*/
+
+ public String getSubclassPropertyTableName(int i) {
+ return subclassTableNameClosure[ subclassPropertyTableNumberClosure[i] ];
+ }
+
+ public Type getDiscriminatorType() {
+ return Hibernate.INTEGER;
+ }
+
+ public String getDiscriminatorSQLValue() {
+ return discriminatorSQLString;
+ }
+
+
+ public String getSubclassForDiscriminatorValue(Object value) {
+ return (String) subclassesByDiscriminatorValue.get(value);
+ }
+
+ public Serializable[] getPropertySpaces() {
+ return spaces; // don't need subclass tables, because they can't appear in conditions
+ }
+
+
+ protected String getTableName(int j) {
+ return naturalOrderTableNames[j];
+ }
+
+ protected String[] getKeyColumns(int j) {
+ return naturalOrderTableKeyColumns[j];
+ }
+
+ protected boolean isTableCascadeDeleteEnabled(int j) {
+ return naturalOrderCascadeDeleteEnabled[j];
+ }
+
+ protected boolean isPropertyOfTable(int property, int j) {
+ return naturalOrderPropertyTableNumbers[property]==j;
+ }
+
+ /**
+ * Load an instance using either the <tt>forUpdateLoader</tt> or the outer joining <tt>loader</tt>,
+ * depending upon the value of the <tt>lock</tt> parameter
+ */
+ /*public Object load(Serializable id, Object optionalObject, LockMode lockMode, SessionImplementor session)
+ throws HibernateException {
+
+ if ( log.isTraceEnabled() ) log.trace( "Materializing entity: " + MessageHelper.infoString(this, id) );
+
+ final UniqueEntityLoader loader = hasQueryLoader() ?
+ getQueryLoader() :
+ this.loader;
+ try {
+
+ final Object result = loader.load(id, optionalObject, session);
+
+ if (result!=null) lock(id, getVersion(result), result, lockMode, session);
+
+ return result;
+
+ }
+ catch (SQLException sqle) {
+ throw new JDBCException( "could not load by id: " + MessageHelper.infoString(this, id), sqle );
+ }
+ }*/
+
+ private static final void reverse(Object[] objects, int len) {
+ Object[] temp = new Object[len];
+ for (int i=0; i<len; i++) {
+ temp[i] = objects[len-i-1];
+ }
+ for (int i=0; i<len; i++) {
+ objects[i] = temp[i];
+ }
+ }
+
+
+ /**
+ * Reverse the first n elements of the incoming array
+ * @param objects
+ * @param n
+ * @return New array with the first n elements in reversed order
+ */
+ private static final String[] reverse(String [] objects, int n) {
+
+ int size = objects.length;
+ String[] temp = new String[size];
+
+ for (int i=0; i<n; i++) {
+ temp[i] = objects[n-i-1];
+ }
+
+ for (int i=n; i < size; i++) {
+ temp[i] = objects[i];
+ }
+
+ return temp;
+ }
+
+ /**
+ * Reverse the first n elements of the incoming array
+ * @param objects
+ * @param n
+ * @return New array with the first n elements in reversed order
+ */
+ private static final String[][] reverse(String[][] objects, int n) {
+ int size = objects.length;
+ String[][] temp = new String[size][];
+ for (int i=0; i<n; i++) {
+ temp[i] = objects[n-i-1];
+ }
+
+ for (int i=n; i<size; i++) {
+ temp[i] = objects[i];
+ }
+
+ return temp;
+ }
+
+
+
+ public String fromTableFragment(String alias) {
+ return getTableName() + ' ' + alias;
+ }
+
+ public String getTableName() {
+ return tableNames[0];
+ }
+
+ private static int getTableId(String tableName, String[] tables) {
+ for ( int j=0; j<tables.length; j++ ) {
+ if ( tableName.equals( tables[j] ) ) {
+ return j;
+ }
+ }
+ throw new AssertionFailure("Table " + tableName + " not found");
+ }
+
+ public void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) {
+ if ( hasSubclasses() ) {
+ select.setExtraSelectList( discriminatorFragment(name), getDiscriminatorAlias() );
+ }
+ }
+
+ private CaseFragment discriminatorFragment(String alias) {
+ CaseFragment cases = getFactory().getDialect().createCaseFragment();
+
+ for ( int i=0; i<discriminatorValues.length; i++ ) {
+ cases.addWhenColumnNotNull(
+ generateTableAlias( alias, notNullColumnTableNumbers[i] ),
+ notNullColumnNames[i],
+ discriminatorValues[i]
+ );
+ }
+
+ return cases;
+ }
+
+ public String filterFragment(String alias) {
+ return hasWhere() ?
+ " and " + getSQLWhereString( generateFilterConditionAlias( alias ) ) :
+ "";
+ }
+
+ public String generateFilterConditionAlias(String rootAlias) {
+ return generateTableAlias( rootAlias, tableSpan-1 );
+ }
+
+ public String[] getIdentifierColumnNames() {
+ return tableKeyColumns[0];
+ }
+
+ public String[] getIdentifierColumnReaderTemplates() {
+ return tableKeyColumnReaderTemplates[0];
+ }
+
+ public String[] getIdentifierColumnReaders() {
+ return tableKeyColumnReaders[0];
+ }
+
+ public String[] toColumns(String alias, String propertyName) throws QueryException {
+
+ if ( ENTITY_CLASS.equals(propertyName) ) {
+ // This doesn't actually seem to work but it *might*
+ // work on some dbs. Also it doesn't work if there
+ // are multiple columns of results because it
+ // is not accounting for the suffix:
+ // return new String[] { getDiscriminatorColumnName() };
+
+ return new String[] { discriminatorFragment(alias).toFragmentString() };
+ }
+ else {
+ return super.toColumns(alias, propertyName);
+ }
+
+ }
+
+ protected int[] getPropertyTableNumbersInSelect() {
+ return propertyTableNumbers;
+ }
+
+ protected int getSubclassPropertyTableNumber(int i) {
+ return subclassPropertyTableNumberClosure[i];
+ }
+
+ public int getTableSpan() {
+ return tableSpan;
+ }
+
+ public boolean isMultiTable() {
+ return true;
+ }
+
+ protected int[] getSubclassColumnTableNumberClosure() {
+ return subclassColumnTableNumberClosure;
+ }
+
+ protected int[] getSubclassFormulaTableNumberClosure() {
+ return subclassFormulaTableNumberClosure;
+ }
+
+ protected int[] getPropertyTableNumbers() {
+ return naturalOrderPropertyTableNumbers;
+ }
+
+ protected String[] getSubclassTableKeyColumns(int j) {
+ return subclassTableKeyColumnClosure[j];
+ }
+
+ public String getSubclassTableName(int j) {
+ return subclassTableNameClosure[j];
+ }
+
+ public int getSubclassTableSpan() {
+ return subclassTableNameClosure.length;
+ }
+
+ protected boolean isSubclassTableLazy(int j) {
+ return subclassTableIsLazyClosure[j];
+ }
+
+
+ protected boolean isClassOrSuperclassTable(int j) {
+ return isClassOrSuperclassTable[j];
+ }
+
+ public String getPropertyTableName(String propertyName) {
+ Integer index = getEntityMetamodel().getPropertyIndexOrNull(propertyName);
+ if ( index == null ) {
+ return null;
+ }
+ return tableNames[ propertyTableNumbers[ index.intValue() ] ];
+ }
+
+ public String[] getConstraintOrderedTableNameClosure() {
+ return constraintOrderedTableNames;
+ }
+
+ public String[][] getContraintOrderedTableKeyColumnClosure() {
+ return constraintOrderedKeyColumnNames;
+ }
+
+ public String getRootTableName() {
+ return naturalOrderTableNames[0];
+ }
+
+ public String getRootTableAlias(String drivingAlias) {
+ return generateTableAlias( drivingAlias, getTableId( getRootTableName(), tableNames ) );
+ }
+
+ public Declarer getSubclassPropertyDeclarer(String propertyPath) {
+ if ( "class".equals( propertyPath ) ) {
+ // special case where we need to force incloude all subclass joins
+ return Declarer.SUBCLASS;
+ }
+ return super.getSubclassPropertyDeclarer( propertyPath );
+ }
+}
14 years, 5 months
Hibernate SVN: r19891 - core/trunk/documentation/envers/src/main/docbook/en-US/content.
by hibernate-commits@lists.jboss.org
Author: adamw
Date: 2010-07-02 08:57:18 -0400 (Fri, 02 Jul 2010)
New Revision: 19891
Modified:
core/trunk/documentation/envers/src/main/docbook/en-US/content/configuration.xml
core/trunk/documentation/envers/src/main/docbook/en-US/content/queries.xml
Log:
HHH-3764, HHH-3765:
documentation
Modified: core/trunk/documentation/envers/src/main/docbook/en-US/content/configuration.xml
===================================================================
--- core/trunk/documentation/envers/src/main/docbook/en-US/content/configuration.xml 2010-07-02 08:54:15 UTC (rev 19890)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/configuration.xml 2010-07-02 12:57:18 UTC (rev 19891)
@@ -177,6 +177,32 @@
be the same as the catalog of the normal tables.
</entry>
</row>
+ <row>
+ <entry>
+ <property>org.hibernate.envers.audit_strategy</property>
+ </entry>
+ <entry>
+ org.hibernate.envers.strategy.DefaultAuditStrategy
+ </entry>
+ <entry>
+ The audit strategy that should be used when persisting audit data. The default stores only the
+ revision, at which an entity was modified. An alternative,
+ <literal>org.hibernate.envers.strategy.ValidTimeAuditStrategy</literal> stores additionaly the
+ end revision, until which the data was valid.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <property>org.hibernate.envers.audit_strategy_valid_time_end_name</property>
+ </entry>
+ <entry>
+ REVEND
+ </entry>
+ <entry>
+ Only valid if the audit strategy is valid-time. Name of the column that will hold the end
+ revision number in audit entities.
+ </entry>
+ </row>
</tbody>
</tgroup>
</table>
Modified: core/trunk/documentation/envers/src/main/docbook/en-US/content/queries.xml
===================================================================
--- core/trunk/documentation/envers/src/main/docbook/en-US/content/queries.xml 2010-07-02 08:54:15 UTC (rev 19890)
+++ core/trunk/documentation/envers/src/main/docbook/en-US/content/queries.xml 2010-07-02 12:57:18 UTC (rev 19891)
@@ -58,6 +58,12 @@
than corresponding queries on "live" data, as they involve correlated subselects.
</para>
+ <para>
+ In the future, queries will be improved both in terms of speed and possibilities, when using the valid-time
+ audit strategy, that is when storing both start and end revisions for entities. See
+ <xref linkend="configuration"/>.
+ </para>
+
<section id="entities-at-revision">
<title>Querying for entities of a class at a given revision</title>
14 years, 5 months
Hibernate SVN: r19890 - in core/trunk: parent and 1 other directory.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2010-07-02 04:54:15 -0400 (Fri, 02 Jul 2010)
New Revision: 19890
Modified:
core/trunk/entitymanager/pom.xml
core/trunk/parent/pom.xml
Log:
HHH-5317 Updated the hibernate-validator dependency to 4.1.0.Final. Added a profile to EM which will add the jaxb classes in case the build is using java 5. HV 4.1.0.Final now uses the provided scope for the jaxb depdencies
Modified: core/trunk/entitymanager/pom.xml
===================================================================
--- core/trunk/entitymanager/pom.xml 2010-07-02 08:31:15 UTC (rev 19889)
+++ core/trunk/entitymanager/pom.xml 2010-07-02 08:54:15 UTC (rev 19890)
@@ -198,5 +198,25 @@
</plugins>
</build>
</profile>
+ <profile>
+ <id>jaxb</id>
+ <activation>
+ <jdk>1.5</jdk>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>javax.xml.bind</groupId>
+ <artifactId>jaxb-api</artifactId>
+ <version>2.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.xml.bind</groupId>
+ <artifactId>jaxb-impl</artifactId>
+ <version>2.1.3</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
</profiles>
</project>
Modified: core/trunk/parent/pom.xml
===================================================================
--- core/trunk/parent/pom.xml 2010-07-02 08:31:15 UTC (rev 19889)
+++ core/trunk/parent/pom.xml 2010-07-02 08:54:15 UTC (rev 19890)
@@ -537,7 +537,7 @@
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
- <version>4.0.2.GA</version>
+ <version>4.1.0.Final</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
14 years, 5 months
Hibernate SVN: r19889 - validator/trunk/hibernate-validator/src/main/resources/org/hibernate/validator.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2010-07-02 04:31:15 -0400 (Fri, 02 Jul 2010)
New Revision: 19889
Added:
validator/trunk/hibernate-validator/src/main/resources/org/hibernate/validator/ValidationMessages_hu.properties
Log:
HV-349 Added hungarian validation messages
Added: validator/trunk/hibernate-validator/src/main/resources/org/hibernate/validator/ValidationMessages_hu.properties
===================================================================
--- validator/trunk/hibernate-validator/src/main/resources/org/hibernate/validator/ValidationMessages_hu.properties (rev 0)
+++ validator/trunk/hibernate-validator/src/main/resources/org/hibernate/validator/ValidationMessages_hu.properties 2010-07-02 08:31:15 UTC (rev 19889)
@@ -0,0 +1,23 @@
+
+
+javax.validation.constraints.AssertFalse.message=hamis kell legyen
+javax.validation.constraints.AssertTrue.message=igaz kell legyen
+javax.validation.constraints.DecimalMax.message=kisebb vagy egyenl\u0151 kell legyen mint {value}
+javax.validation.constraints.DecimalMin.message=nagyobb vagy egyenl\u0151 kell legyen mint {value}
+javax.validation.constraints.Digits.message=a sz\u00e1mform\u00e1tum nem felel meg a k\u00f6vetkez\u0151 form\u00e1nak: <{integer} sz\u00e1mjegy>.<{fraction} tizedesjegy>
+javax.validation.constraints.Future.message=a j\u00f6v\u0151ben kell lennie
+javax.validation.constraints.Max.message=kisebb vagy egyenl\u0151 kell legyen mint {value}
+javax.validation.constraints.Min.message=nagyobb vagy egyenl\u0151 kell legyen mint {value}
+javax.validation.constraints.NotNull.message=nem lehet null-\u00e9rt\u00e9k
+javax.validation.constraints.Null.message=null-\u00e9rt\u00e9knek kell lennie
+javax.validation.constraints.Past.message=a m\u00faltban kell lennie
+javax.validation.constraints.Pattern.message=meg kell felelnie a "{regexp}" regul\u00e1ris kifejez\u00e9snek
+javax.validation.constraints.Size.message=a m\u00e9retnek {min} \u00e9s {max} k\u00f6z\u00f6tt kell lennie
+org.hibernate.validator.constraints.Email.message=nem felel meg az email c\u00edmek form\u00e1tum\u00e1nak
+org.hibernate.validator.constraints.Length.message=a hossznak {min} \u00e9s {max} k\u00f6z\u00f6tt kell lennie
+org.hibernate.validator.constraints.NotBlank.message=nem lehet \u00fcres
+org.hibernate.validator.constraints.NotEmpty.message=nem lehet \u00fcres
+org.hibernate.validator.constraints.Range.message=az \u00e9rt\u00e9knek {min} \u00e9s {max} k\u00f6z\u00f6tt kell lennie
+org.hibernate.validator.constraints.URL.message=\u00e9rv\u00e9nyes URL-nek kell lennie
+org.hibernate.validator.constraints.CreditCardNumber.message=hib\u00e1s hitelk\u00e1rtyasz\u00e1m
+org.hibernate.validator.constraints.ScriptAssert.message=script kifejez\u00e9s "{script}" nem \u00e9rt\u00e9kel\u0151d\u00f6tt ki igazz\u00e1
14 years, 5 months
Hibernate SVN: r19888 - in core/trunk/envers/src: main/java/org/hibernate/envers/configuration and 10 other directories.
by hibernate-commits@lists.jboss.org
Author: adamw
Date: 2010-07-02 02:32:13 -0400 (Fri, 02 Jul 2010)
New Revision: 19888
Added:
core/trunk/envers/src/main/java/org/hibernate/envers/strategy/
core/trunk/envers/src/main/java/org/hibernate/envers/strategy/AuditStrategy.java
core/trunk/envers/src/main/java/org/hibernate/envers/strategy/DefaultAuditStrategy.java
core/trunk/envers/src/main/java/org/hibernate/envers/strategy/ValidTimeAuditStrategy.java
Modified:
core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditConfiguration.java
core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditEntitiesConfiguration.java
core/trunk/envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
core/trunk/envers/src/main/java/org/hibernate/envers/query/impl/AbstractAuditQuery.java
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/AbstractAuditWorkUnit.java
core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java
core/trunk/envers/src/main/java/org/hibernate/envers/tools/query/QueryBuilder.java
core/trunk/envers/src/test/java/org/hibernate/envers/test/AbstractEntityTest.java
core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/customtype/CompositeTestUserType.java
core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/manytomany/sametable/BasicSametable.java
core/trunk/envers/src/test/java/org/hibernate/envers/test/performance/AbstractPerformanceTest.java
core/trunk/envers/src/test/resources/hibernate.test.cfg.xml
core/trunk/envers/src/test/resources/testng.xml
Log:
HHH-3764:
- adding an end-revision column to the audit entities if the appropraite strategy is used
HHH-3765:
- filling in the end-revision column on audited entities changes
- applying patch by Stephanie Pau - thanks!
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditConfiguration.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditConfiguration.java 2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditConfiguration.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -27,10 +27,12 @@
import java.util.Properties;
import java.util.WeakHashMap;
+import org.hibernate.MappingException;
import org.hibernate.envers.entities.EntitiesConfigurations;
import org.hibernate.envers.revisioninfo.RevisionInfoNumberReader;
import org.hibernate.envers.revisioninfo.RevisionInfoQueryCreator;
import org.hibernate.envers.synchronization.AuditProcessManager;
+import org.hibernate.envers.strategy.AuditStrategy;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.AnnotationConfiguration;
@@ -38,11 +40,13 @@
/**
* @author Adam Warski (adam at warski dot org)
+ * @author Stephanie Pau at Markit Group Plc
*/
public class AuditConfiguration {
private final GlobalConfiguration globalCfg;
private final AuditEntitiesConfiguration auditEntCfg;
private final AuditProcessManager auditProcessManager;
+ private final AuditStrategy auditStrategy;
private final EntitiesConfigurations entCfg;
private final RevisionInfoQueryCreator revisionInfoQueryCreator;
private final RevisionInfoNumberReader revisionInfoNumberReader;
@@ -71,7 +75,11 @@
return revisionInfoNumberReader;
}
- @SuppressWarnings({"unchecked"})
+ public AuditStrategy getAuditStrategy() {
+ return auditStrategy;
+ }
+
+ @SuppressWarnings({ "unchecked" })
public AuditConfiguration(Configuration cfg) {
Properties properties = cfg.getProperties();
@@ -81,6 +89,14 @@
auditEntCfg = new AuditEntitiesConfiguration(properties, revInfoCfgResult.getRevisionInfoEntityName());
globalCfg = new GlobalConfiguration(properties);
auditProcessManager = new AuditProcessManager(revInfoCfgResult.getRevisionInfoGenerator());
+
+ try {
+ Class auditStrategyClass = Thread.currentThread().getContextClassLoader().loadClass(auditEntCfg.getAuditStrategyName());
+ auditStrategy = (AuditStrategy) auditStrategyClass.newInstance();
+ } catch (Exception e) {
+ throw new MappingException(String.format("Unable to create AuditStrategy[%s] instance." , auditEntCfg.getAuditStrategyName()));
+ }
+
revisionInfoQueryCreator = revInfoCfgResult.getRevisionInfoQueryCreator();
revisionInfoNumberReader = revInfoCfgResult.getRevisionInfoNumberReader();
entCfg = new EntitiesConfigurator().configure(cfg, reflectionManager, globalCfg, auditEntCfg,
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditEntitiesConfiguration.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditEntitiesConfiguration.java 2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/configuration/AuditEntitiesConfiguration.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -25,18 +25,28 @@
import static org.hibernate.envers.tools.Tools.getProperty;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
+import org.hibernate.MappingException;
+import org.hibernate.envers.strategy.DefaultAuditStrategy;
+import org.hibernate.envers.strategy.ValidTimeAuditStrategy;
+
/**
* Configuration of versions entities - names of fields, entities and tables created to store versioning information.
* @author Adam Warski (adam at warski dot org)
+ * @author Stephanie Pau at Markit Group Plc
*/
public class AuditEntitiesConfiguration {
private final String auditTablePrefix;
private final String auditTableSuffix;
+ private final String auditStrategyName;
private final String originalIdPropName;
private final String revisionFieldName;
@@ -50,6 +60,8 @@
private final Map<String, String> customAuditTablesNames;
+ private final String revisionEndFieldName;
+
public AuditEntitiesConfiguration(Properties properties, String revisionInfoEntityName) {
this.revisionInfoEntityName = revisionInfoEntityName;
@@ -62,6 +74,11 @@
"org.hibernate.envers.auditTableSuffix",
"_AUD");
+ auditStrategyName = getProperty(properties,
+ "org.hibernate.envers.audit_strategy",
+ "org.hibernate.envers.audit_strategy",
+ DefaultAuditStrategy.class.getName());
+
originalIdPropName = "originalId";
revisionFieldName = getProperty(properties,
@@ -75,6 +92,11 @@
"REVTYPE");
revisionTypePropType = "byte";
+ revisionEndFieldName = getProperty(properties,
+ "org.hibernate.envers.audit_strategy_valid_time_end_name",
+ "org.hibernate.envers.audit_strategy_valid_time_end_name",
+ "REVEND");
+
customAuditTablesNames = new HashMap<String, String>();
revisionNumberPath = originalIdPropName + "." + revisionFieldName + ".id";
@@ -133,4 +155,12 @@
return customHistoryTableName;
}
+
+ public String getAuditStrategyName() {
+ return auditStrategyName;
+ }
+
+ public String getRevisionEndFieldName() {
+ return revisionEndFieldName;
+ }
}
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java 2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/configuration/metadata/AuditMetadataGenerator.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -38,6 +38,7 @@
import org.hibernate.envers.entities.mapper.ExtendedPropertyMapper;
import org.hibernate.envers.entities.mapper.MultiPropertyMapper;
import org.hibernate.envers.entities.mapper.SubclassPropertyMapper;
+import org.hibernate.envers.strategy.ValidTimeAuditStrategy;
import org.hibernate.envers.tools.StringTools;
import org.hibernate.envers.tools.Triple;
import org.hibernate.envers.RelationTargetAuditMode;
@@ -53,6 +54,7 @@
* @author Adam Warski (adam at warski dot org)
* @author Sebastian Komander
* @author Tomasz Bech
+ * @author Stephanie Pau at Markit Group Plc
*/
public final class AuditMetadataGenerator {
private static final Logger log = LoggerFactory.getLogger(AuditMetadataGenerator.class);
@@ -124,8 +126,23 @@
Element revTypeProperty = MetadataTools.addProperty(any_mapping, verEntCfg.getRevisionTypePropName(),
verEntCfg.getRevisionTypePropType(), true, false);
revTypeProperty.addAttribute("type", "org.hibernate.envers.entities.RevisionTypeType");
+
+ // Adding the end revision, if appropriate
+ addEndRevision(any_mapping);
}
+ private void addEndRevision(Element any_mapping) {
+ // Add the end-revision field, if the appropriate strategy is used.
+ if (ValidTimeAuditStrategy.class.getName().equals(verEntCfg.getAuditStrategyName())) {
+ Element end_rev_mapping = (Element) revisionInfoRelationMapping.clone();
+ end_rev_mapping.setName("many-to-one");
+ end_rev_mapping.addAttribute("name", verEntCfg.getRevisionEndFieldName());
+ MetadataTools.addOrModifyColumn(end_rev_mapping, verEntCfg.getRevisionEndFieldName());
+
+ any_mapping.add(end_rev_mapping);
+ }
+ }
+
@SuppressWarnings({"unchecked"})
void addValue(Element parent, Value value, CompositeMapperBuilder currentMapper, String entityName,
EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData,
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/query/impl/AbstractAuditQuery.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/query/impl/AbstractAuditQuery.java 2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/query/impl/AbstractAuditQuery.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -24,9 +24,7 @@
package org.hibernate.envers.query.impl;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
@@ -80,16 +78,8 @@
}
protected List buildAndExecuteQuery() {
- StringBuilder querySb = new StringBuilder();
- Map<String, Object> queryParamValues = new HashMap<String, Object>();
+ Query query = qb.toQuery(versionsReader.getSession());
- qb.build(querySb, queryParamValues);
-
- Query query = versionsReader.getSession().createQuery(querySb.toString());
- for (Map.Entry<String, Object> paramValue : queryParamValues.entrySet()) {
- query.setParameter(paramValue.getKey(), paramValue.getValue());
- }
-
setQueryProperties(query);
return query.list();
Added: core/trunk/envers/src/main/java/org/hibernate/envers/strategy/AuditStrategy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/strategy/AuditStrategy.java (rev 0)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/strategy/AuditStrategy.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -0,0 +1,39 @@
+package org.hibernate.envers.strategy;
+
+import org.hibernate.Session;
+import org.hibernate.envers.configuration.AuditConfiguration;
+import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
+
+import java.io.Serializable;
+
+/**
+ * Behaviours of different audit strategy for populating audit data.
+ *
+ * @author Stephanie Pau
+ * @author Adam Warski (adam at warski dot org)
+ */
+public interface AuditStrategy {
+ /**
+ * Perform the persistence of audited data for regular entities.
+ *
+ * @param session Session, which can be used to persist the data.
+ * @param entityName Name of the entity, in which the audited change happens
+ * @param auditCfg Audit configuration
+ * @param id Id of the entity.
+ * @param data Audit data to persist
+ * @param revision Current revision data
+ */
+ void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data,
+ Object revision);
+
+ /**
+ * Perform the persistence of audited data for collection ("middle") entities.
+ *
+ * @param session Session, which can be used to persist the data.
+ * @param auditCfg Audit configuration
+ * @param persistentCollectionChangeData Collection change data to be persisted.
+ * @param revision Current revision data
+ */
+ void performCollectionChange(Session session, AuditConfiguration auditCfg,
+ PersistentCollectionChangeData persistentCollectionChangeData, Object revision);
+}
Property changes on: core/trunk/envers/src/main/java/org/hibernate/envers/strategy/AuditStrategy.java
___________________________________________________________________
Name: svn:executable
+ *
Added: core/trunk/envers/src/main/java/org/hibernate/envers/strategy/DefaultAuditStrategy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/strategy/DefaultAuditStrategy.java (rev 0)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/strategy/DefaultAuditStrategy.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -0,0 +1,25 @@
+package org.hibernate.envers.strategy;
+
+import org.hibernate.Session;
+import org.hibernate.envers.configuration.AuditConfiguration;
+import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
+
+import java.io.Serializable;
+
+/**
+ * Default strategy is to simply persist the audit data.
+ *
+ * @author Adam Warski
+ * @author Stephanie Pau
+ */
+public class DefaultAuditStrategy implements AuditStrategy {
+ public void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data,
+ Object revision) {
+ session.save(auditCfg.getAuditEntCfg().getAuditEntityName(entityName), data);
+ }
+
+ public void performCollectionChange(Session session, AuditConfiguration auditCfg,
+ PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
+ session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
+ }
+}
Property changes on: core/trunk/envers/src/main/java/org/hibernate/envers/strategy/DefaultAuditStrategy.java
___________________________________________________________________
Name: svn:executable
+ *
Added: core/trunk/envers/src/main/java/org/hibernate/envers/strategy/ValidTimeAuditStrategy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/strategy/ValidTimeAuditStrategy.java (rev 0)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/strategy/ValidTimeAuditStrategy.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -0,0 +1,105 @@
+package org.hibernate.envers.strategy;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+import org.hibernate.Session;
+import org.hibernate.envers.RevisionType;
+import org.hibernate.envers.configuration.AuditConfiguration;
+import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
+import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
+import org.hibernate.envers.entities.mapper.id.IdMapper;
+import org.hibernate.envers.tools.query.QueryBuilder;
+
+/**
+ * Audit strategy which additionally manages the end-revision number: updates the end-revision field on the last
+ * revision that was persisted before the current one.
+ *
+ * @author Stephanie Pau
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class ValidTimeAuditStrategy implements AuditStrategy {
+ public void perform(Session session, String entityName, AuditConfiguration auditCfg, Serializable id, Object data,
+ Object revision) {
+ AuditEntitiesConfiguration audEntCfg = auditCfg.getAuditEntCfg();
+ String auditedEntityName = audEntCfg.getAuditEntityName(entityName);
+
+ // Update the end date of the previous row if this operation is expected to have a previous row
+ if (getRevisionType(auditCfg, data) != RevisionType.ADD) {
+ /*
+ Constructing a query:
+ select e from audited_ent e where e.end_rev is null and e.id = :id
+ */
+
+ QueryBuilder qb = new QueryBuilder(auditedEntityName, "e");
+
+ // e.id = :id
+ IdMapper idMapper = auditCfg.getEntCfg().get(entityName).getIdMapper();
+ idMapper.addIdEqualsToQuery(qb.getRootParameters(), id, auditCfg.getAuditEntCfg().getOriginalIdPropName(), true);
+
+ updateLastRevision(session, auditCfg, qb, id, auditedEntityName, revision);
+ }
+
+ // Save the audit data
+ session.save(auditedEntityName, data);
+ }
+
+ @SuppressWarnings({"unchecked"})
+ public void performCollectionChange(Session session, AuditConfiguration auditCfg,
+ PersistentCollectionChangeData persistentCollectionChangeData, Object revision) {
+ // Update the end date of the previous row if this operation is expected to have a previous row
+ if (getRevisionType(auditCfg, persistentCollectionChangeData.getData()) != RevisionType.ADD) {
+ /*
+ Constructing a query (there are multiple id fields):
+ select e from audited_middle_ent e where e.end_rev is null and e.id1 = :id1 and e.id2 = :id2 ...
+ */
+
+ QueryBuilder qb = new QueryBuilder(persistentCollectionChangeData.getEntityName(), "e");
+
+ // Adding a parameter for each id component, except the rev number
+ String originalIdPropName = auditCfg.getAuditEntCfg().getOriginalIdPropName();
+ Map<String, Object> originalId = (Map<String, Object>) persistentCollectionChangeData.getData().get(
+ originalIdPropName);
+ for (Map.Entry<String, Object> originalIdEntry : originalId.entrySet()) {
+ if (!auditCfg.getAuditEntCfg().getRevisionFieldName().equals(originalIdEntry.getKey())) {
+ qb.getRootParameters().addWhereWithParam(originalIdPropName + "." + originalIdEntry.getKey(),
+ true, "=", originalIdEntry.getValue());
+ }
+ }
+
+ updateLastRevision(session, auditCfg, qb, originalId, persistentCollectionChangeData.getEntityName(), revision);
+ }
+
+ // Save the audit data
+ session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
+ }
+
+ @SuppressWarnings({"unchecked"})
+ private RevisionType getRevisionType(AuditConfiguration auditCfg, Object data) {
+ return (RevisionType) ((Map<String, Object>) data).get(auditCfg.getAuditEntCfg().getRevisionTypePropName());
+ }
+
+ @SuppressWarnings({"unchecked"})
+ private void updateLastRevision(Session session, AuditConfiguration auditCfg, QueryBuilder qb,
+ Object id, String auditedEntityName, Object revision) {
+ String revisionEndFieldName = auditCfg.getAuditEntCfg().getRevisionEndFieldName();
+
+ // e.end_rev is null
+ qb.getRootParameters().addWhere(revisionEndFieldName, true, "is", "null", false);
+
+ List l = qb.toQuery(session).list();
+
+ // There should be one entry
+ if (l.size() == 1) {
+ // Setting the end revision to be the current rev
+ Object previousData = l.get(0);
+ ((Map<String, Object>) previousData).put(revisionEndFieldName, revision);
+
+ // Saving the previous version
+ session.save(auditedEntityName, previousData);
+ } else {
+ throw new RuntimeException("Cannot find previous revision for entity " + auditedEntityName + " and id " + id);
+ }
+ }
+}
Property changes on: core/trunk/envers/src/main/java/org/hibernate/envers/strategy/ValidTimeAuditStrategy.java
___________________________________________________________________
Name: svn:executable
+ *
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/AbstractAuditWorkUnit.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/AbstractAuditWorkUnit.java 2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/AbstractAuditWorkUnit.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -33,15 +33,18 @@
import org.hibernate.Session;
import org.hibernate.engine.SessionImplementor;
+import org.hibernate.envers.strategy.AuditStrategy;
/**
* @author Adam Warski (adam at warski dot org)
+ * @author Stephanie Pau at Markit Group Plc
*/
public abstract class AbstractAuditWorkUnit implements AuditWorkUnit {
protected final SessionImplementor sessionImplementor;
protected final AuditConfiguration verCfg;
protected final Serializable id;
protected final String entityName;
+ protected final AuditStrategy auditStrategy;
private Object performedData;
@@ -51,6 +54,7 @@
this.verCfg = verCfg;
this.id = id;
this.entityName = entityName;
+ this.auditStrategy = verCfg.getAuditStrategy();
}
protected void fillDataWithId(Map<String, Object> data, Object revision, RevisionType revisionType) {
@@ -67,7 +71,7 @@
public void perform(Session session, Object revisionData) {
Map<String, Object> data = generateData(revisionData);
- session.save(verCfg.getAuditEntCfg().getAuditEntityName(getEntityName()), data);
+ auditStrategy.perform(session, getEntityName(), verCfg, id, data, revisionData);
setPerformed(data);
}
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java 2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/synchronization/work/PersistentCollectionChangeWorkUnit.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -29,6 +29,7 @@
import java.util.HashMap;
import java.util.ArrayList;
+import org.hibernate.envers.RevisionType;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.configuration.AuditEntitiesConfiguration;
import org.hibernate.envers.entities.mapper.PersistentCollectionChangeData;
@@ -84,7 +85,7 @@
((Map<String, Object>) persistentCollectionChangeData.getData().get(entitiesCfg.getOriginalIdPropName()))
.put(entitiesCfg.getRevisionFieldName(), revisionData);
- session.save(persistentCollectionChangeData.getEntityName(), persistentCollectionChangeData.getData());
+ auditStrategy.performCollectionChange(session, verCfg, persistentCollectionChangeData, revisionData);
}
}
@@ -137,13 +138,24 @@
// Including only those original changes, which are not overshadowed by new ones.
for (PersistentCollectionChangeData originalCollectionChangeData : original.getCollectionChanges()) {
- if (!newChangesIdMap.containsKey(getOriginalId(originalCollectionChangeData))) {
+ Object originalOriginalId = getOriginalId(originalCollectionChangeData);
+ if (!newChangesIdMap.containsKey(originalOriginalId)) {
mergedChanges.add(originalCollectionChangeData);
+ } else {
+ // If the changes collide, checking if the first one isn't a DEL, and the second a subsequent ADD
+ // If so, removing the change alltogether.
+ String revTypePropName = verCfg.getAuditEntCfg().getRevisionTypePropName();
+ if (RevisionType.ADD.equals(newChangesIdMap.get(originalOriginalId).getData().get(
+ revTypePropName)) && RevisionType.DEL.equals(originalCollectionChangeData.getData().get(
+ revTypePropName))) {
+ newChangesIdMap.remove(originalOriginalId);
+ }
}
}
- // Finally adding all of the new changes to the end of the list
- mergedChanges.addAll(getCollectionChanges());
+ // Finally adding all of the new changes to the end of the list (the map values may differ from
+ // getCollectionChanges() because of the last operation above).
+ mergedChanges.addAll(newChangesIdMap.values());
return new PersistentCollectionChangeWorkUnit(sessionImplementor, entityName, verCfg, id, mergedChanges,
referencingPropertyName);
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/tools/query/QueryBuilder.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/tools/query/QueryBuilder.java 2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/tools/query/QueryBuilder.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -24,9 +24,12 @@
package org.hibernate.envers.tools.query;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.hibernate.Query;
+import org.hibernate.Session;
import org.hibernate.envers.tools.MutableInteger;
import org.hibernate.envers.tools.Pair;
import org.hibernate.envers.tools.StringTools;
@@ -197,4 +200,18 @@
return orderList;
}
+
+ public Query toQuery(Session session) {
+ StringBuilder querySb = new StringBuilder();
+ Map<String, Object> queryParamValues = new HashMap<String, Object>();
+
+ build(querySb, queryParamValues);
+
+ Query query = session.createQuery(querySb.toString());
+ for (Map.Entry<String, Object> paramValue : queryParamValues.entrySet()) {
+ query.setParameter(paramValue.getKey(), paramValue.getValue());
+ }
+
+ return query;
+ }
}
Modified: core/trunk/envers/src/test/java/org/hibernate/envers/test/AbstractEntityTest.java
===================================================================
--- core/trunk/envers/src/test/java/org/hibernate/envers/test/AbstractEntityTest.java 2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/test/java/org/hibernate/envers/test/AbstractEntityTest.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -30,9 +30,7 @@
import org.hibernate.envers.AuditReader;
import org.hibernate.envers.AuditReaderFactory;
import org.hibernate.envers.event.AuditEventListener;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.AfterClass;
+import org.testng.annotations.*;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.event.*;
@@ -78,17 +76,23 @@
}
@BeforeClass
- public void init() throws IOException {
- init(true);
+ @Parameters("auditStrategy")
+ public void init(@Optional String auditStrategy) throws IOException {
+ init(true, auditStrategy);
}
- protected void init(boolean audited) throws IOException {
+ protected void init(boolean audited, String auditStrategy) throws IOException {
this.audited = audited;
cfg = new Ejb3Configuration();
if (audited) {
initListeners();
}
+
+ if (auditStrategy != null && !"".equals(auditStrategy)) {
+ cfg.setProperty("org.hibernate.envers.audit_strategy", auditStrategy);
+ }
+
cfg.configure("hibernate.test.cfg.xml");
configure(cfg);
emf = cfg.buildEntityManagerFactory();
Modified: core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/customtype/CompositeTestUserType.java
===================================================================
--- core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/customtype/CompositeTestUserType.java 2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/test/java/org/hibernate/envers/test/entities/customtype/CompositeTestUserType.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -90,9 +90,6 @@
public Object nullSafeGet(final ResultSet rs, final String[] names,
final SessionImplementor session,
final Object owner) throws HibernateException, SQLException {
- if (rs.wasNull()) {
- return null;
- }
final String prop1 = rs.getString(names[0]);
if (prop1 == null) {
return null;
Modified: core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/manytomany/sametable/BasicSametable.java
===================================================================
--- core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/manytomany/sametable/BasicSametable.java 2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/test/java/org/hibernate/envers/test/integration/manytomany/sametable/BasicSametable.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -66,7 +66,7 @@
session.createSQLQuery("DROP TABLE children").executeUpdate();
session.createSQLQuery("CREATE TABLE children(parent_id integer, child1_id integer NULL, child2_id integer NULL)").executeUpdate();
session.createSQLQuery("DROP TABLE children_AUD").executeUpdate();
- session.createSQLQuery("CREATE TABLE children_AUD(REV integer NOT NULL, REVTYPE tinyint, " +
+ session.createSQLQuery("CREATE TABLE children_AUD(REV integer NOT NULL, REVEND integer, REVTYPE tinyint, " +
"parent_id integer, child1_id integer NULL, child2_id integer NULL)").executeUpdate();
em.getTransaction().commit();
em.clear();
Modified: core/trunk/envers/src/test/java/org/hibernate/envers/test/performance/AbstractPerformanceTest.java
===================================================================
--- core/trunk/envers/src/test/java/org/hibernate/envers/test/performance/AbstractPerformanceTest.java 2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/test/java/org/hibernate/envers/test/performance/AbstractPerformanceTest.java 2010-07-02 06:32:13 UTC (rev 19888)
@@ -88,11 +88,11 @@
List<Long> unauditedRuns = new ArrayList<Long>();
List<Long> auditedRuns = new ArrayList<Long>();
- init(true);
+ init(true, null);
long audited = run(numberOfRuns, auditedRuns);
close();
- init(false);
+ init(false, null);
long unaudited = run(numberOfRuns, unauditedRuns);
close();
Modified: core/trunk/envers/src/test/resources/hibernate.test.cfg.xml
===================================================================
--- core/trunk/envers/src/test/resources/hibernate.test.cfg.xml 2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/test/resources/hibernate.test.cfg.xml 2010-07-02 06:32:13 UTC (rev 19888)
@@ -23,6 +23,8 @@
<!--<property name="connection.username">root</property>-->
<!--<property name="connection.password"></property>-->
+ <!--<property name="org.hibernate.envers.audit_strategy">org.hibernate.envers.strategy.ValidTimeAuditStrategy</property>-->
+
<!--<property name="hibernate.jdbc.batch_size">100</property>-->
<!--<event type="post-insert">
Modified: core/trunk/envers/src/test/resources/testng.xml
===================================================================
--- core/trunk/envers/src/test/resources/testng.xml 2010-07-01 20:29:38 UTC (rev 19887)
+++ core/trunk/envers/src/test/resources/testng.xml 2010-07-02 06:32:13 UTC (rev 19888)
@@ -1,8 +1,5 @@
-<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
-
-<suite name="Envers">
- <test name="All">
- <packages>
+<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" [
+ <!ENTITY packages '
<package name="org.hibernate.envers.test.integration.accesstype" />
<package name="org.hibernate.envers.test.integration.auditReader" />
<package name="org.hibernate.envers.test.integration.basic" />
@@ -71,6 +68,19 @@
<package name="org.hibernate.envers.test.integration.secondary.ids" />
<package name="org.hibernate.envers.test.integration.serialization" />
<package name="org.hibernate.envers.test.integration.superclass" />
+ '>
+]>
+
+<suite name="Envers">
+ <test name="All">
+ <packages>
+ &packages;
</packages>
</test>
+ <test name="ValidTimeAuditStrategy">
+ <parameter name="auditStrategy" value="org.hibernate.envers.strategy.ValidTimeAuditStrategy" />
+ <packages>
+ &packages;
+ </packages>
+ </test>
</suite>
14 years, 5 months
Hibernate SVN: r19887 - search/trunk/hibernate-search.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2010-07-01 16:29:38 -0400 (Thu, 01 Jul 2010)
New Revision: 19887
Modified:
search/trunk/hibernate-search/pom.xml
Log:
HSEARCH-487 Updated release plugin configuration
Modified: search/trunk/hibernate-search/pom.xml
===================================================================
--- search/trunk/hibernate-search/pom.xml 2010-07-01 20:29:15 UTC (rev 19886)
+++ search/trunk/hibernate-search/pom.xml 2010-07-01 20:29:38 UTC (rev 19887)
@@ -187,7 +187,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<configuration>
- <goals>deploy javadoc:javadoc org.jboss.maven.plugins:maven-jdocbook-plugin:2.2.0:resources org.jboss.maven.plugins:maven-jdocbook-plugin:2.2.0:generate assembly:assembly</goals>
+ <goals>deploy javadoc:javadoc org.jboss.maven.plugins:maven-jdocbook-plugin:2.2.3:translate org.jboss.maven.plugins:maven-jdocbook-plugin:2.2.3:resources org.jboss.maven.plugins:maven-jdocbook-plugin:2.2.3:generate assembly:assembly</goals>
</configuration>
</plugin>
<plugin>
14 years, 5 months