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.SQLInsert;
|
||||
import org.hibernate.annotations.SQLUpdate;
|
||||
import org.hibernate.annotations.Subselect;
|
||||
import org.hibernate.annotations.Synchronize;
|
||||
import org.hibernate.annotations.Tables;
|
||||
import org.hibernate.annotations.Tuplizer;
|
||||
import org.hibernate.annotations.Tuplizers;
|
||||
|
@ -120,7 +122,9 @@ public class EntityBinder {
|
|||
private boolean cacheLazyProperty;
|
||||
private AccessType propertyAccessType = AccessType.DEFAULT;
|
||||
private boolean wrapIdsInEmbeddedComponents;
|
||||
|
||||
private String subselect;
|
||||
|
||||
|
||||
public boolean wrapIdsInEmbeddedComponents() {
|
||||
return wrapIdsInEmbeddedComponents;
|
||||
}
|
||||
|
@ -257,6 +261,7 @@ public class EntityBinder {
|
|||
SQLDelete sqlDelete = annotatedClass.getAnnotation( SQLDelete.class );
|
||||
SQLDeleteAll sqlDeleteAll = annotatedClass.getAnnotation( SQLDeleteAll.class );
|
||||
Loader loader = annotatedClass.getAnnotation( Loader.class );
|
||||
|
||||
if ( sqlInsert != null ) {
|
||||
persistentClass.setCustomSQLInsert( sqlInsert.sql().trim(), sqlInsert.callable(),
|
||||
ExecuteUpdateResultCheckStyle.parse( sqlInsert.check().toString().toLowerCase() )
|
||||
|
@ -282,6 +287,20 @@ public class EntityBinder {
|
|||
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
|
||||
if ( annotatedClass.isAnnotationPresent( Tuplizers.class ) ) {
|
||||
for (Tuplizer tuplizer : annotatedClass.getAnnotation( Tuplizers.class ).value()) {
|
||||
|
@ -474,7 +493,8 @@ public class EntityBinder {
|
|||
uniqueConstraints,
|
||||
constraints,
|
||||
denormalizedSuperclassTable,
|
||||
mappings
|
||||
mappings,
|
||||
this.subselect
|
||||
);
|
||||
|
||||
if ( persistentClass instanceof TableOwner ) {
|
||||
|
@ -701,7 +721,8 @@ public class EntityBinder {
|
|||
uniqueConstraintHolders,
|
||||
null,
|
||||
null,
|
||||
mappings
|
||||
mappings,
|
||||
null
|
||||
);
|
||||
|
||||
//no check constraints available on joins
|
||||
|
|
|
@ -183,7 +183,8 @@ public class TableBinder {
|
|||
uniqueConstraints,
|
||||
constraints,
|
||||
denormalizedSuperTable,
|
||||
mappings
|
||||
mappings,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -200,7 +201,7 @@ public class TableBinder {
|
|||
|
||||
return new AssociationTableNameSource( name, logicalName );
|
||||
}
|
||||
|
||||
|
||||
public static Table buildAndFillTable(
|
||||
String schema,
|
||||
String catalog,
|
||||
|
@ -210,7 +211,8 @@ public class TableBinder {
|
|||
List<UniqueConstraintHolder> uniqueConstraints,
|
||||
String constraints,
|
||||
Table denormalizedSuperTable,
|
||||
ExtendedMappings mappings) {
|
||||
ExtendedMappings mappings,
|
||||
String subselect) {
|
||||
schema = BinderHelper.isDefault( schema ) ? mappings.getSchemaName() : schema;
|
||||
catalog = BinderHelper.isDefault( catalog ) ? mappings.getCatalogName() : catalog;
|
||||
|
||||
|
@ -226,7 +228,7 @@ public class TableBinder {
|
|||
catalog,
|
||||
realTableName,
|
||||
isAbstract,
|
||||
null, // subselect
|
||||
subselect,
|
||||
denormalizedSuperTable
|
||||
);
|
||||
}
|
||||
|
@ -235,7 +237,7 @@ public class TableBinder {
|
|||
schema,
|
||||
catalog,
|
||||
realTableName,
|
||||
null, // subselect
|
||||
subselect,
|
||||
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