This is an automated email from the ASF dual-hosted git repository. borinquenkid pushed a commit to branch 8.0.x-hibernate7 in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 2ed90bdadf5c18b317808cd5129bcd40cf45af27 Author: Walter Duque de Estrada <[email protected]> AuthorDate: Mon Feb 23 12:57:55 2026 -0600 removed deprecated implementation from GrailsHibernateTemplate --- grails-data-hibernate7/REMOVAL_WARNINGS.md | 7 - .../orm/hibernate/GrailsHibernateTemplate.java | 8 +- .../cfg/domainbinding/util/GrailsOneToOne.java | 274 ------------ .../hibernate/GrailsHibernateTemplateSpec.groovy | 480 +++++++++++++++++++++ 4 files changed, 485 insertions(+), 284 deletions(-) diff --git a/grails-data-hibernate7/REMOVAL_WARNINGS.md b/grails-data-hibernate7/REMOVAL_WARNINGS.md index 28ef82e37c..64fa40fb75 100644 --- a/grails-data-hibernate7/REMOVAL_WARNINGS.md +++ b/grails-data-hibernate7/REMOVAL_WARNINGS.md @@ -9,17 +9,10 @@ Generated from: Hibernate `7.1.11.Final` | Fully Qualified Class | Line | Warning | |---|---|---| -| `org.grails.orm.hibernate.GrailsHibernateTemplate` | 388 | `<T>get(Class<T>,Object) in Session` has been deprecated and marked for removal | -| `org.grails.orm.hibernate.GrailsHibernateTemplate` | 419 | `<T>get(Class<T>,Object,LockOptions) in Session` has been deprecated and marked for removal | -| `org.grails.orm.hibernate.GrailsHibernateTemplate` | 419 | `LockOptions in org.hibernate` has been deprecated and marked for removal | -| `org.grails.orm.hibernate.GrailsHibernateTemplate` | 467 | `LockOptions in org.hibernate` has been deprecated and marked for removal | -| `org.grails.orm.hibernate.GrailsHibernateTemplate` | 467 | `refresh(Object,LockOptions) in Session` has been deprecated and marked for removal | | `org.grails.orm.hibernate.HibernateDatastore` | 686 | `SchemaAutoTooling in org.hibernate.boot` has been deprecated and marked for removal | | `org.grails.orm.hibernate.HibernateDatastore` | 687 | `SchemaAutoTooling in org.hibernate.boot` has been deprecated and marked for removal | | `org.grails.orm.hibernate.HibernateDatastore` | 689 | `SchemaAutoTooling in org.hibernate.boot` has been deprecated and marked for removal | | `org.grails.orm.hibernate.HibernateDatastore` | 690 | `SchemaAutoTooling in org.hibernate.boot` has been deprecated and marked for removal | -| `org.grails.orm.hibernate.cfg.domainbinding.util.GrailsOneToOne` | 98 | `createGenerator(Dialect,RootClass) in KeyValue` has been deprecated and marked for removal | -| `org.grails.orm.hibernate.cfg.domainbinding.util.GrailsOneToOne` | 99 | `createGenerator(Dialect,RootClass) in SimpleValue` has been deprecated and marked for removal | | `org.grails.orm.hibernate.support.ClosureEventListener` | 342 | `EntityMetamodel in org.hibernate.tuple.entity` has been deprecated and marked for removal | | `org.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor` | 286 | `EntityMetamodel in org.hibernate.tuple.entity` has been deprecated and marked for removal | | `org.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor` | 305 | `EntityMetamodel in org.hibernate.tuple.entity` has been deprecated and marked for removal | diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTemplate.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTemplate.java index 6e8e3411b1..4132e76824 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTemplate.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTemplate.java @@ -384,10 +384,12 @@ public class GrailsHibernateTemplate implements IHibernateTemplate { new CloseSuppressingInvocationHandler(session)); } + @Deprecated(since = "7.0", forRemoval = true) public <T> T get(final Class<T> entityClass, final Serializable id) throws DataAccessException { - return doExecute(session -> session.get(entityClass, id), true); + return doExecute(session -> session.find(entityClass, id), true); } + @Deprecated(since = "7.0", forRemoval = true) public <T> T get(final Class<T> entityClass, final Serializable id, final LockMode mode) { return lock(entityClass, id, mode); } @@ -416,7 +418,7 @@ public class GrailsHibernateTemplate implements IHibernateTemplate { public <T> T lock(final Class<T> entityClass, final Serializable id, final LockMode lockMode) throws DataAccessException { - return doExecute(session -> session.get(entityClass, id, new LockOptions(lockMode)), true); + return doExecute(session -> session.find(entityClass, id, lockMode), true); } public <T> List<T> loadAll(final Class<T> entityClass) throws DataAccessException { @@ -464,7 +466,7 @@ public class GrailsHibernateTemplate implements IHibernateTemplate { if (lockMode == null) { session.refresh(entity); } else { - session.refresh(entity, new LockOptions(lockMode)); + session.refresh(entity,lockMode); } return null; }, diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/GrailsOneToOne.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/GrailsOneToOne.java deleted file mode 100644 index 30772772f2..0000000000 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/GrailsOneToOne.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.grails.orm.hibernate.cfg.domainbinding.util; - -import java.util.List; -import java.util.Set; -import org.hibernate.FetchMode; -import org.hibernate.MappingException; -import org.hibernate.boot.spi.MetadataBuildingContext; -import org.hibernate.dialect.Dialect; -import org.hibernate.generator.Generator; -import org.hibernate.mapping.Column; -import org.hibernate.mapping.ForeignKey; -import org.hibernate.mapping.GeneratorSettings; -import org.hibernate.mapping.OneToOne; -import org.hibernate.mapping.PersistentClass; -import org.hibernate.mapping.Property; -import org.hibernate.mapping.RootClass; -import org.hibernate.mapping.Selectable; -import org.hibernate.mapping.Table; -import org.hibernate.mapping.Value; -import org.hibernate.mapping.ValueVisitor; -import org.hibernate.metamodel.mapping.JdbcMapping; -import org.hibernate.service.ServiceRegistry; -import org.hibernate.type.MappingContext; -import org.hibernate.type.Type; - -public class GrailsOneToOne implements GrailsToOne { - private final OneToOne delegate; - - public GrailsOneToOne(MetadataBuildingContext buildingContext, Table table, PersistentClass owner) - throws MappingException { - this.delegate = new OneToOne(buildingContext, table, owner); - } - - @Override - public void setFetchMode(FetchMode joinedFetch) { - delegate.setFetchMode(joinedFetch); - } - - @Override - public boolean isLazy() { - return delegate.isLazy(); - } - - @Override - public void setLazy(boolean lazy) { - delegate.setLazy(lazy); - } - - @Override - public ForeignKey createForeignKeyOfEntity(String entityName, List<Column> referencedColumns) { - return delegate.createForeignKeyOfEntity(entityName, referencedColumns); - } - - @Override - public ForeignKey createForeignKeyOfEntity(String entityName) { - return delegate.createForeignKeyOfEntity(entityName); - } - - @Override - public boolean isCascadeDeleteEnabled() { - return delegate.isCascadeDeleteEnabled(); - } - - @Override - public NullValueSemantic getNullValueSemantic() { - return delegate.getNullValueSemantic(); - } - - @Override - public String getNullValue() { - return delegate.getNullValue(); - } - - @Override - public boolean isUpdateable() { - return delegate.isUpdateable(); - } - - @Override - public Generator createGenerator(Dialect dialect, RootClass rootClass) { - return delegate.createGenerator(dialect, rootClass); - } - - @Override - public Generator createGenerator( - Dialect dialect, RootClass rootClass, Property property, GeneratorSettings defaults) { - return delegate.createGenerator(dialect, rootClass, property, defaults); - } - - @Override - public boolean isSorted() { - return delegate.isSorted(); - } - - @Override - public int[] sortProperties() { - return delegate.sortProperties(); - } - - @Override - public int getColumnSpan() { - return delegate.getColumnSpan(); - } - - @Override - public List<Selectable> getSelectables() { - return delegate.getSelectables(); - } - - @Override - public List<Column> getColumns() { - return delegate.getColumns(); - } - - @Override - public List<Selectable> getVirtualSelectables() { - return delegate.getVirtualSelectables(); - } - - @Override - public List<Column> getConstraintColumns() { - return delegate.getConstraintColumns(); - } - - @Override - public Type getType() throws MappingException { - return delegate.getType(); - } - - @Override - public JdbcMapping getSelectableType(MappingContext mappingContext, int index) - throws MappingException { - return delegate.getSelectableType(mappingContext, index); - } - - @Override - public FetchMode getFetchMode() { - return delegate.getFetchMode(); - } - - @Override - public Table getTable() { - return delegate.getTable(); - } - - @Override - public boolean hasFormula() { - return delegate.hasFormula(); - } - - @Override - public boolean isAlternateUniqueKey() { - return delegate.isAlternateUniqueKey(); - } - - @Override - public boolean isPartitionKey() { - return delegate.isPartitionKey(); - } - - @Override - public boolean isNullable() { - return delegate.isNullable(); - } - - @Override - public void createForeignKey() { - delegate.createForeignKey(); - } - - @Override - public void createUniqueKey(MetadataBuildingContext context) { - delegate.createUniqueKey(context); - } - - @Override - public boolean isSimpleValue() { - return delegate.isSimpleValue(); - } - - @Override - public boolean isValid(MappingContext mappingContext) throws MappingException { - return delegate.isValid(mappingContext); - } - - @Override - public void setTypeUsingReflection(String className, String propertyName) - throws MappingException { - delegate.setTypeUsingReflection(className, propertyName); - } - - @Override - public Object accept(ValueVisitor visitor) { - return delegate.accept(visitor); - } - - @Override - public boolean isSame(Value other) { - return delegate.isSame(other); - } - - @Override - public boolean[] getColumnInsertability() { - return delegate.getColumnInsertability(); - } - - @Override - public boolean hasAnyInsertableColumns() { - return delegate.hasAnyInsertableColumns(); - } - - @Override - public boolean[] getColumnUpdateability() { - return delegate.getColumnUpdateability(); - } - - @Override - public boolean hasAnyUpdatableColumns() { - return delegate.hasAnyUpdatableColumns(); - } - - @Override - public MetadataBuildingContext getBuildingContext() { - return delegate.getBuildingContext(); - } - - @Override - public ServiceRegistry getServiceRegistry() { - return delegate.getServiceRegistry(); - } - - @Override - public Value copy() { - return delegate.copy(); - } - - @Override - public boolean isColumnInsertable(int index) { - return delegate.isColumnInsertable(index); - } - - @Override - public boolean isColumnUpdateable(int index) { - return delegate.isColumnUpdateable(index); - } - - @Override - public String getExtraCreateTableInfo() { - return delegate.getExtraCreateTableInfo(); - } - - @Override - public void checkColumnDuplication(Set<String> distinctColumns, String owner) { - delegate.checkColumnDuplication(distinctColumns, owner); - } -} diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/GrailsHibernateTemplateSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/GrailsHibernateTemplateSpec.groovy new file mode 100644 index 0000000000..386d240f78 --- /dev/null +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/GrailsHibernateTemplateSpec.groovy @@ -0,0 +1,480 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.grails.orm.hibernate + +import grails.gorm.annotation.Entity +import grails.gorm.hibernate.HibernateEntity +import grails.gorm.specs.HibernateGormDatastoreSpec +import org.hibernate.LockMode +import org.testcontainers.DockerClientFactory +import org.testcontainers.containers.PostgreSQLContainer +import org.testcontainers.spock.Testcontainers +import spock.lang.Requires +import spock.lang.Shared + +@Testcontainers +@Requires({ + try { DockerClientFactory.instance().client(); true } catch (ignored) { false } +}) +class GrailsHibernateTemplateSpec extends HibernateGormDatastoreSpec { + + @Shared PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:16") + + GrailsHibernateTemplate template + + @Override + void setupSpec() { + manager.grailsConfig = [ + 'dataSource.url' : postgres.jdbcUrl, + 'dataSource.driverClassName' : postgres.driverClassName, + 'dataSource.username' : postgres.username, + 'dataSource.password' : postgres.password, + 'dataSource.dbCreate' : 'create-drop', + 'hibernate.dialect' : 'org.hibernate.dialect.PostgreSQLDialect', + 'hibernate.hbm2ddl.auto' : 'create', + ] + manager.addAllDomainClasses([TemplateBook]) + } + + void setup() { + template = new GrailsHibernateTemplate(sessionFactory) + } + + void cleanup() { + session.clear() + } + + // ------------------------------------------------------------------------- + // Flush mode constants + // ------------------------------------------------------------------------- + + void "flush mode constants have expected values"() { + expect: + GrailsHibernateTemplate.FLUSH_NEVER == 0 + GrailsHibernateTemplate.FLUSH_AUTO == 1 + GrailsHibernateTemplate.FLUSH_EAGER == 2 + GrailsHibernateTemplate.FLUSH_COMMIT == 3 + GrailsHibernateTemplate.FLUSH_ALWAYS == 4 + } + + void "default flush mode is FLUSH_AUTO"() { + expect: + template.flushMode == GrailsHibernateTemplate.FLUSH_AUTO + } + + void "setFlushMode and getFlushMode round-trip"() { + when: + template.flushMode = GrailsHibernateTemplate.FLUSH_COMMIT + + then: + template.flushMode == GrailsHibernateTemplate.FLUSH_COMMIT + } + + // ------------------------------------------------------------------------- + // Constructor / configuration + // ------------------------------------------------------------------------- + + void "constructor exposes the sessionFactory"() { + expect: + template.sessionFactory == sessionFactory + } + + void "cacheQueries defaults to false and can be changed"() { + expect: + !template.cacheQueries + + when: + template.cacheQueries = true + + then: + template.cacheQueries + } + + void "exposeNativeSession defaults to true and can be changed"() { + expect: + template.exposeNativeSession + + when: + template.exposeNativeSession = false + + then: + !template.exposeNativeSession + } + + void "osivReadOnly defaults to false and can be toggled"() { + expect: + !template.osivReadOnly + + when: + template.osivReadOnly = true + + then: + template.osivReadOnly + } + + // ------------------------------------------------------------------------- + // execute(Closure) — read-only HQL query + // ------------------------------------------------------------------------- + + void "execute with Closure runs query inside a session"() { + given: + TemplateBook.withTransaction { + new TemplateBook(title: "Groovy in Action", author: "Dierk König").save(flush: true, failOnError: true) + } + + when: + Long count = template.execute { sess -> + sess.createQuery("select count(b) from TemplateBook b", Long).uniqueResult() + } + + then: + count >= 1L + } + + void "execute with HibernateCallback runs query inside a session"() { + given: + TemplateBook.withTransaction { + new TemplateBook(title: "Making Java Groovy", author: "Ken Kousen").save(flush: true, failOnError: true) + } + + when: + Long count = template.execute({ sess -> + sess.createQuery("select count(b) from TemplateBook b", Long).uniqueResult() + } as GrailsHibernateTemplate.HibernateCallback) + + then: + count >= 1L + } + + // ------------------------------------------------------------------------- + // executeWithNewSession + // ------------------------------------------------------------------------- + + void "executeWithNewSession uses an isolated session"() { + given: "an entity committed in the current transaction" + TemplateBook saved = TemplateBook.withTransaction { + new TemplateBook(title: "Grails in Action", author: "Glen Smith").save(flush: true, failOnError: true) + } + + when: "a separate new session queries for that committed data" + Long count = template.executeWithNewSession { sess -> + sess.createQuery("select count(b) from TemplateBook b where b.title = :t", Long) + .setParameter("t", "Grails in Action") + .uniqueResult() + } + + then: "the new session can see the committed row" + count == 1L + } + + // ------------------------------------------------------------------------- + // get + // ------------------------------------------------------------------------- + + void "get returns the entity by id"() { + given: + TemplateBook saved = TemplateBook.withTransaction { + new TemplateBook(title: "Programming Groovy 2", author: "Venkat Subramaniam").save(flush: true, failOnError: true) + } + session.clear() + + when: + TemplateBook found = template.get(TemplateBook, saved.id) + + then: + found != null + found.id == saved.id + found.title == "Programming Groovy 2" + } + + void "get returns null for non-existent id"() { + expect: + template.get(TemplateBook, -1L) == null + } + + void "get with LockMode returns the entity"() { + given: + TemplateBook saved = TemplateBook.withTransaction { + new TemplateBook(title: "Clean Code", author: "Robert Martin").save(flush: true, failOnError: true) + } + session.clear() + + when: + TemplateBook found = TemplateBook.withTransaction { + template.get(TemplateBook, saved.id, LockMode.PESSIMISTIC_WRITE) + } + + then: + found != null + found.id == saved.id + } + + // ------------------------------------------------------------------------- + // load (lazy reference) + // ------------------------------------------------------------------------- + + void "load returns a reference for a persisted entity"() { + given: + TemplateBook saved = TemplateBook.withTransaction { + new TemplateBook(title: "Effective Java", author: "Joshua Bloch").save(flush: true, failOnError: true) + } + session.clear() + + when: + TemplateBook ref = template.load(TemplateBook, saved.id) + + then: + ref != null + ref.id == saved.id + } + + // ------------------------------------------------------------------------- + // loadAll + // ------------------------------------------------------------------------- + + void "loadAll returns all persisted instances of the class"() { + given: + TemplateBook.withTransaction { + new TemplateBook(title: "Book A", author: "Author A").save(flush: true, failOnError: true) + new TemplateBook(title: "Book B", author: "Author B").save(flush: true, failOnError: true) + } + + when: + List<TemplateBook> all = template.loadAll(TemplateBook) + + then: + all.size() >= 2 + all.every { it instanceof TemplateBook } + } + + // ------------------------------------------------------------------------- + // persist + // ------------------------------------------------------------------------- + + void "persist saves a new entity and assigns an id"() { + given: + TemplateBook book = new TemplateBook(title: "Domain-Driven Design", author: "Eric Evans") + + when: + TemplateBook.withTransaction { + template.persist(book) + template.flush() + } + + then: + book.id != null + } + + // ------------------------------------------------------------------------- + // merge + // ------------------------------------------------------------------------- + + void "merge returns a managed copy of the detached entity"() { + given: + TemplateBook saved = TemplateBook.withTransaction { + new TemplateBook(title: "Refactoring", author: "Martin Fowler").save(flush: true, failOnError: true) + } + session.clear() + saved.title = "Refactoring (2nd Edition)" + + when: + TemplateBook managed = TemplateBook.withTransaction { + template.merge(saved) as TemplateBook + } + + then: + managed != null + managed.id == saved.id + managed.title == "Refactoring (2nd Edition)" + } + + // ------------------------------------------------------------------------- + // remove + // ------------------------------------------------------------------------- + + void "remove deletes the entity"() { + given: + TemplateBook saved = TemplateBook.withTransaction { + new TemplateBook(title: "The Pragmatic Programmer", author: "Dave Thomas").save(flush: true, failOnError: true) + } + Long id = saved.id + + when: + TemplateBook.withTransaction { + TemplateBook managed = template.get(TemplateBook, id) + template.remove(managed) + template.flush() + } + + then: + template.get(TemplateBook, id) == null + } + + // ------------------------------------------------------------------------- + // contains / evict + // ------------------------------------------------------------------------- + + void "contains returns true for a managed entity and false after evict"() { + given: + TemplateBook saved = TemplateBook.withTransaction { + new TemplateBook(title: "Head First Java", author: "Kathy Sierra").save(flush: true, failOnError: true) + } + + when: + boolean before = template.contains(saved) + template.evict(saved) + boolean after = template.contains(saved) + + then: + before + !after + } + + // ------------------------------------------------------------------------- + // refresh + // ------------------------------------------------------------------------- + + void "refresh reloads the entity state from the database"() { + given: + TemplateBook saved = TemplateBook.withTransaction { + new TemplateBook(title: "Spring in Action", author: "Craig Walls").save(flush: true, failOnError: true) + } + + when: "the in-memory state is mutated without flushing" + saved.title = "mutated" + + and: "refresh restores the persisted state" + template.refresh(saved) + + then: + saved.title == "Spring in Action" + } + + // ------------------------------------------------------------------------- + // flush / clear + // ------------------------------------------------------------------------- + + void "flush() flushes pending changes to the database"() { + given: + TemplateBook book = new TemplateBook(title: "Seven Languages", author: "Bruce Tate") + TemplateBook.withTransaction { + template.persist(book) + template.flush() + } + + when: + Long count = template.execute { sess -> + sess.createQuery("select count(b) from TemplateBook b where b.title = :t", Long) + .setParameter("t", "Seven Languages") + .uniqueResult() + } + + then: + count == 1L + } + + void "clear() detaches all entities from the session"() { + given: + TemplateBook saved = TemplateBook.withTransaction { + new TemplateBook(title: "Java Concurrency in Practice", author: "Brian Goetz").save(flush: true, failOnError: true) + } + + when: + boolean before = template.contains(saved) + template.clear() + boolean after = template.contains(saved) + + then: + before + !after + } + + // ------------------------------------------------------------------------- + // lock(Object, LockMode) + // ------------------------------------------------------------------------- + + void "lock(entity, lockMode) acquires a pessimistic lock on the entity"() { + given: + TemplateBook saved = TemplateBook.withTransaction { + new TemplateBook(title: "Java Performance", author: "Scott Oaks").save(flush: true, failOnError: true) + } + + when: + TemplateBook.withTransaction { + template.lock(saved, LockMode.PESSIMISTIC_WRITE) + } + + then: + noExceptionThrown() + } + + // ------------------------------------------------------------------------- + // lock(Class, Serializable, LockMode) + // ------------------------------------------------------------------------- + + void "lock(class, id, lockMode) retrieves and locks the entity"() { + given: + TemplateBook saved = TemplateBook.withTransaction { + new TemplateBook(title: "Thinking in Java", author: "Bruce Eckel").save(flush: true, failOnError: true) + } + session.clear() + + when: + TemplateBook locked = TemplateBook.withTransaction { + template.lock(TemplateBook, saved.id, LockMode.PESSIMISTIC_READ) + } + + then: + locked != null + locked.id == saved.id + } + + // ------------------------------------------------------------------------- + // getSession + // ------------------------------------------------------------------------- + + void "getSession returns the current Hibernate session"() { + when: + def sess = template.session + + then: + sess != null + } + + // ------------------------------------------------------------------------- + // applyFlushModeOnlyToNonExistingTransactions flag + // ------------------------------------------------------------------------- + + void "applyFlushModeOnlyToNonExistingTransactions can be toggled"() { + expect: + !template.applyFlushModeOnlyToNonExistingTransactions + + when: + template.applyFlushModeOnlyToNonExistingTransactions = true + + then: + template.applyFlushModeOnlyToNonExistingTransactions + } +} + +@Entity +class TemplateBook implements HibernateEntity<TemplateBook> { + String title + String author +}
