HHH-4374 Subselect. Also implemented Synchronize annotation.
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18884 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
97444b2d2d
commit
03649bc406
|
@ -0,0 +1,18 @@
|
||||||
|
package org.hibernate.annotations;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.TYPE;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map an immutable and read-only entity to a given SQL subselect expression:
|
||||||
|
* @author Sharath Reddy
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Target(TYPE)
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface Subselect {
|
||||||
|
String value();
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.hibernate.annotations;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.TYPE;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that auto-flush happens correctly and that queries against the derived
|
||||||
|
* entity do not return stale data.
|
||||||
|
*
|
||||||
|
* Mostly used with Subselect.
|
||||||
|
*
|
||||||
|
* @author Sharath Reddy
|
||||||
|
*/
|
||||||
|
@Target(TYPE)
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface Synchronize {
|
||||||
|
String [] value();
|
||||||
|
}
|
|
@ -54,6 +54,8 @@ import org.hibernate.annotations.SQLDelete;
|
||||||
import org.hibernate.annotations.SQLDeleteAll;
|
import org.hibernate.annotations.SQLDeleteAll;
|
||||||
import org.hibernate.annotations.SQLInsert;
|
import org.hibernate.annotations.SQLInsert;
|
||||||
import org.hibernate.annotations.SQLUpdate;
|
import org.hibernate.annotations.SQLUpdate;
|
||||||
|
import org.hibernate.annotations.Subselect;
|
||||||
|
import org.hibernate.annotations.Synchronize;
|
||||||
import org.hibernate.annotations.Tables;
|
import org.hibernate.annotations.Tables;
|
||||||
import org.hibernate.annotations.Tuplizer;
|
import org.hibernate.annotations.Tuplizer;
|
||||||
import org.hibernate.annotations.Tuplizers;
|
import org.hibernate.annotations.Tuplizers;
|
||||||
|
@ -120,7 +122,9 @@ public class EntityBinder {
|
||||||
private boolean cacheLazyProperty;
|
private boolean cacheLazyProperty;
|
||||||
private AccessType propertyAccessType = AccessType.DEFAULT;
|
private AccessType propertyAccessType = AccessType.DEFAULT;
|
||||||
private boolean wrapIdsInEmbeddedComponents;
|
private boolean wrapIdsInEmbeddedComponents;
|
||||||
|
private String subselect;
|
||||||
|
|
||||||
|
|
||||||
public boolean wrapIdsInEmbeddedComponents() {
|
public boolean wrapIdsInEmbeddedComponents() {
|
||||||
return wrapIdsInEmbeddedComponents;
|
return wrapIdsInEmbeddedComponents;
|
||||||
}
|
}
|
||||||
|
@ -257,6 +261,7 @@ public class EntityBinder {
|
||||||
SQLDelete sqlDelete = annotatedClass.getAnnotation( SQLDelete.class );
|
SQLDelete sqlDelete = annotatedClass.getAnnotation( SQLDelete.class );
|
||||||
SQLDeleteAll sqlDeleteAll = annotatedClass.getAnnotation( SQLDeleteAll.class );
|
SQLDeleteAll sqlDeleteAll = annotatedClass.getAnnotation( SQLDeleteAll.class );
|
||||||
Loader loader = annotatedClass.getAnnotation( Loader.class );
|
Loader loader = annotatedClass.getAnnotation( Loader.class );
|
||||||
|
|
||||||
if ( sqlInsert != null ) {
|
if ( sqlInsert != null ) {
|
||||||
persistentClass.setCustomSQLInsert( sqlInsert.sql().trim(), sqlInsert.callable(),
|
persistentClass.setCustomSQLInsert( sqlInsert.sql().trim(), sqlInsert.callable(),
|
||||||
ExecuteUpdateResultCheckStyle.parse( sqlInsert.check().toString().toLowerCase() )
|
ExecuteUpdateResultCheckStyle.parse( sqlInsert.check().toString().toLowerCase() )
|
||||||
|
@ -282,6 +287,20 @@ public class EntityBinder {
|
||||||
persistentClass.setLoaderName( loader.namedQuery() );
|
persistentClass.setLoaderName( loader.namedQuery() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( annotatedClass.isAnnotationPresent( Synchronize.class )) {
|
||||||
|
Synchronize synchronizedWith = annotatedClass.getAnnotation(Synchronize.class);
|
||||||
|
|
||||||
|
String [] tables = synchronizedWith.value();
|
||||||
|
for (String table : tables) {
|
||||||
|
persistentClass.addSynchronizedTable(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( annotatedClass.isAnnotationPresent(Subselect.class )) {
|
||||||
|
Subselect subselect = annotatedClass.getAnnotation(Subselect.class);
|
||||||
|
this.subselect = subselect.value();
|
||||||
|
}
|
||||||
|
|
||||||
//tuplizers
|
//tuplizers
|
||||||
if ( annotatedClass.isAnnotationPresent( Tuplizers.class ) ) {
|
if ( annotatedClass.isAnnotationPresent( Tuplizers.class ) ) {
|
||||||
for (Tuplizer tuplizer : annotatedClass.getAnnotation( Tuplizers.class ).value()) {
|
for (Tuplizer tuplizer : annotatedClass.getAnnotation( Tuplizers.class ).value()) {
|
||||||
|
@ -474,7 +493,8 @@ public class EntityBinder {
|
||||||
uniqueConstraints,
|
uniqueConstraints,
|
||||||
constraints,
|
constraints,
|
||||||
denormalizedSuperclassTable,
|
denormalizedSuperclassTable,
|
||||||
mappings
|
mappings,
|
||||||
|
this.subselect
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( persistentClass instanceof TableOwner ) {
|
if ( persistentClass instanceof TableOwner ) {
|
||||||
|
@ -701,7 +721,8 @@ public class EntityBinder {
|
||||||
uniqueConstraintHolders,
|
uniqueConstraintHolders,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
mappings
|
mappings,
|
||||||
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
//no check constraints available on joins
|
//no check constraints available on joins
|
||||||
|
|
|
@ -183,7 +183,8 @@ public class TableBinder {
|
||||||
uniqueConstraints,
|
uniqueConstraints,
|
||||||
constraints,
|
constraints,
|
||||||
denormalizedSuperTable,
|
denormalizedSuperTable,
|
||||||
mappings
|
mappings,
|
||||||
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +201,7 @@ public class TableBinder {
|
||||||
|
|
||||||
return new AssociationTableNameSource( name, logicalName );
|
return new AssociationTableNameSource( name, logicalName );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Table buildAndFillTable(
|
public static Table buildAndFillTable(
|
||||||
String schema,
|
String schema,
|
||||||
String catalog,
|
String catalog,
|
||||||
|
@ -210,7 +211,8 @@ public class TableBinder {
|
||||||
List<UniqueConstraintHolder> uniqueConstraints,
|
List<UniqueConstraintHolder> uniqueConstraints,
|
||||||
String constraints,
|
String constraints,
|
||||||
Table denormalizedSuperTable,
|
Table denormalizedSuperTable,
|
||||||
ExtendedMappings mappings) {
|
ExtendedMappings mappings,
|
||||||
|
String subselect) {
|
||||||
schema = BinderHelper.isDefault( schema ) ? mappings.getSchemaName() : schema;
|
schema = BinderHelper.isDefault( schema ) ? mappings.getSchemaName() : schema;
|
||||||
catalog = BinderHelper.isDefault( catalog ) ? mappings.getCatalogName() : catalog;
|
catalog = BinderHelper.isDefault( catalog ) ? mappings.getCatalogName() : catalog;
|
||||||
|
|
||||||
|
@ -226,7 +228,7 @@ public class TableBinder {
|
||||||
catalog,
|
catalog,
|
||||||
realTableName,
|
realTableName,
|
||||||
isAbstract,
|
isAbstract,
|
||||||
null, // subselect
|
subselect,
|
||||||
denormalizedSuperTable
|
denormalizedSuperTable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -235,7 +237,7 @@ public class TableBinder {
|
||||||
schema,
|
schema,
|
||||||
catalog,
|
catalog,
|
||||||
realTableName,
|
realTableName,
|
||||||
null, // subselect
|
subselect,
|
||||||
isAbstract
|
isAbstract
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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.subselect;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sharath Reddy
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class Bid {
|
||||||
|
|
||||||
|
private int id;
|
||||||
|
private long itemId;
|
||||||
|
private double amount;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
public long getItemId() {
|
||||||
|
return itemId;
|
||||||
|
}
|
||||||
|
public void setItemId(long itemId) {
|
||||||
|
this.itemId = itemId;
|
||||||
|
}
|
||||||
|
public double getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
public void setAmount(double val) {
|
||||||
|
this.amount = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* 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.subselect;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Subselect;
|
||||||
|
import org.hibernate.annotations.Synchronize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sharath Reddy
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Subselect("select item.name as name, max(bid.amount) as amount from item, bid where bid.itemId = item.id group by item.name")
|
||||||
|
@Synchronize({"Item", "Bid"})
|
||||||
|
public class HighestBid {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private double amount;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String val) {
|
||||||
|
this.name = val;
|
||||||
|
}
|
||||||
|
public double getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
public void setAmount(double amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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.subselect;
|
||||||
|
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sharath Reddy
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
public class Item {
|
||||||
|
|
||||||
|
private long id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public void setId(long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* 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.subselect;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.Query;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.Transaction;
|
||||||
|
import org.hibernate.test.annotations.TestCase;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sharath Reddy
|
||||||
|
*/
|
||||||
|
public class SubselectTest extends TestCase {
|
||||||
|
|
||||||
|
public void testSubselectWithSynchronize() {
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
Transaction tx = s.beginTransaction();
|
||||||
|
tx.begin();
|
||||||
|
|
||||||
|
//We don't use auto-generated ids because these seem to cause the session to flush.
|
||||||
|
//We want to test that the session flushes because of the 'synchronize' annotation
|
||||||
|
long itemId = 1;
|
||||||
|
Item item = new Item();
|
||||||
|
item.setName("widget");
|
||||||
|
item.setId(itemId);
|
||||||
|
s.save(item);
|
||||||
|
|
||||||
|
Bid bid1 = new Bid();
|
||||||
|
bid1.setAmount(100.0);
|
||||||
|
bid1.setItemId(itemId);
|
||||||
|
bid1.setId(1);
|
||||||
|
s.save(bid1);
|
||||||
|
|
||||||
|
Bid bid2 = new Bid();
|
||||||
|
bid2.setAmount(200.0);
|
||||||
|
bid2.setItemId(itemId);
|
||||||
|
bid2.setId(2);
|
||||||
|
s.save(bid2);
|
||||||
|
|
||||||
|
//Because we use 'synchronize' annotation, this query should trigger session flush
|
||||||
|
Query query = s.createQuery("from HighestBid b where b.name = :name");
|
||||||
|
query.setParameter("name", "widget", Hibernate.STRING);
|
||||||
|
HighestBid highestBid = (HighestBid) query.list().iterator().next();
|
||||||
|
|
||||||
|
assertEquals(200.0, highestBid.getAmount());
|
||||||
|
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[]{
|
||||||
|
Item.class,
|
||||||
|
Bid.class,
|
||||||
|
HighestBid.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue