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:
Sharath Reddy 2010-02-25 13:12:27 +00:00
parent 97444b2d2d
commit 03649bc406
8 changed files with 346 additions and 8 deletions

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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

View File

@ -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
); );
} }

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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
};
}
}