Re-enabled additional tests
This commit is contained in:
parent
3aa875b037
commit
77d870f08c
|
@ -12,11 +12,9 @@ import org.hibernate.jpa.boot.spi.ProviderChecker;
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.logger.Triggerable;
|
import org.hibernate.testing.logger.Triggerable;
|
||||||
import org.hibernate.testing.orm.logger.LogInspector;
|
|
||||||
import org.hibernate.testing.orm.logger.LoggerInspectionExtension;
|
import org.hibernate.testing.orm.logger.LoggerInspectionExtension;
|
||||||
import org.hibernate.testing.orm.logger.Inspector;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
@ -27,15 +25,18 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
*
|
*
|
||||||
* @author Gail Badner
|
* @author Gail Badner
|
||||||
*/
|
*/
|
||||||
@ExtendWith(LoggerInspectionExtension.class)
|
|
||||||
public class DeprecatedProviderCheckerTest {
|
public class DeprecatedProviderCheckerTest {
|
||||||
final static String DEPRECATED_PROVIDER_NAME = "org.hibernate.ejb.HibernatePersistence";
|
final static String DEPRECATED_PROVIDER_NAME = "org.hibernate.ejb.HibernatePersistence";
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
public LoggerInspectionExtension logger = LoggerInspectionExtension
|
||||||
|
.builder().setLogger(
|
||||||
|
HEMLogging.messageLogger( ProviderChecker.class.getName() )
|
||||||
|
).build();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-13027")
|
@TestForIssue(jiraKey = "HHH-13027")
|
||||||
public void testDeprecatedProvider(@LogInspector Inspector logger) {
|
public void testDeprecatedProvider() {
|
||||||
logger.init( HEMLogging.messageLogger( ProviderChecker.class.getName() ) );
|
|
||||||
|
|
||||||
Triggerable triggerable = logger.watchForLogMessages( "HHH015016" );
|
Triggerable triggerable = logger.watchForLogMessages( "HHH015016" );
|
||||||
triggerable.reset();
|
triggerable.reset();
|
||||||
assertTrue( ProviderChecker.hibernateProviderNamesContain( DEPRECATED_PROVIDER_NAME ) );
|
assertTrue( ProviderChecker.hibernateProviderNamesContain( DEPRECATED_PROVIDER_NAME ) );
|
||||||
|
|
|
@ -22,32 +22,32 @@ import org.hibernate.internal.HEMLogging;
|
||||||
import org.hibernate.jpa.boot.spi.ProviderChecker;
|
import org.hibernate.jpa.boot.spi.ProviderChecker;
|
||||||
|
|
||||||
import org.hibernate.testing.jta.JtaAwareConnectionProviderImpl;
|
import org.hibernate.testing.jta.JtaAwareConnectionProviderImpl;
|
||||||
import org.hibernate.testing.jta.TestingJtaPlatformImpl;
|
|
||||||
import org.hibernate.testing.logger.Triggerable;
|
import org.hibernate.testing.logger.Triggerable;
|
||||||
import org.hibernate.testing.orm.jpa.NonStringValueSettingProvider;
|
import org.hibernate.testing.orm.jpa.NonStringValueSettingProvider;
|
||||||
import org.hibernate.testing.orm.logger.Inspector;
|
|
||||||
import org.hibernate.testing.orm.logger.LogInspector;
|
|
||||||
import org.hibernate.testing.orm.logger.LoggerInspectionExtension;
|
import org.hibernate.testing.orm.logger.LoggerInspectionExtension;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
import static org.hamcrest.core.Is.is;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.core.Is.is;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrea Boriero
|
* @author Andrea Boriero
|
||||||
*/
|
*/
|
||||||
@ExtendWith(LoggerInspectionExtension.class)
|
|
||||||
public abstract class AbstractJtaBatchTest {
|
public abstract class AbstractJtaBatchTest {
|
||||||
|
|
||||||
protected Triggerable triggerable;
|
protected Triggerable triggerable;
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
public LoggerInspectionExtension logger = LoggerInspectionExtension
|
||||||
|
.builder().setLogger(
|
||||||
|
HEMLogging.messageLogger( ProviderChecker.class.getName() )
|
||||||
|
).build();
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp(@LogInspector Inspector logInspector) {
|
public void setUp() {
|
||||||
logInspector.init( HEMLogging.messageLogger( ProviderChecker.class.getName() ) );
|
triggerable = logger.watchForLogMessages(
|
||||||
triggerable = logInspector.watchForLogMessages(
|
|
||||||
"HHH000352: Unable to release batch statement..." );
|
"HHH000352: Unable to release batch statement..." );
|
||||||
triggerable.reset();
|
triggerable.reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||||
|
|
||||||
<hibernate-mapping package="org.hibernate.test.stateless">
|
<hibernate-mapping package="org.hibernate.orm.test.stateless">
|
||||||
|
|
||||||
<class name="Contact">
|
<class name="Contact">
|
||||||
<id name="id">
|
<id name="id">
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stateless;
|
package org.hibernate.orm.test.stateless;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stateless;
|
package org.hibernate.orm.test.stateless;
|
||||||
|
|
||||||
|
|
||||||
public class Country {
|
public class Country {
|
|
@ -15,7 +15,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<hibernate-mapping
|
<hibernate-mapping
|
||||||
package="org.hibernate.test.stateless">
|
package="org.hibernate.orm.test.stateless">
|
||||||
|
|
||||||
<class name="Document">
|
<class name="Document">
|
||||||
<id name="name"/>
|
<id name="name"/>
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//$Id: Document.java 8057 2005-08-31 23:19:53Z oneovthafew $
|
//$Id: Document.java 8057 2005-08-31 23:19:53Z oneovthafew $
|
||||||
package org.hibernate.test.stateless;
|
package org.hibernate.orm.test.stateless;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stateless;
|
package org.hibernate.orm.test.stateless;
|
||||||
|
|
||||||
|
|
||||||
public class Org {
|
public class Org {
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//$Id: Paper.java 8048 2005-08-30 21:27:17Z epbernard $
|
//$Id: Paper.java 8048 2005-08-30 21:27:17Z epbernard $
|
||||||
package org.hibernate.test.stateless;
|
package org.hibernate.orm.test.stateless;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -11,7 +11,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stateless;
|
package org.hibernate.orm.test.stateless;
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
|
@ -24,11 +24,13 @@ import javax.persistence.Table;
|
||||||
import org.hibernate.StatelessSession;
|
import org.hibernate.StatelessSession;
|
||||||
import org.hibernate.dialect.H2Dialect;
|
import org.hibernate.dialect.H2Dialect;
|
||||||
|
|
||||||
import org.hibernate.testing.RequiresDialect;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||||
import org.junit.After;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.junit.Before;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
@ -37,18 +39,18 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
* @author Andrea Boriero
|
* @author Andrea Boriero
|
||||||
*/
|
*/
|
||||||
@RequiresDialect(H2Dialect.class)
|
@RequiresDialect(H2Dialect.class)
|
||||||
public class StatelessDoWorkTest extends BaseCoreFunctionalTestCase {
|
@DomainModel(
|
||||||
|
annotatedClasses = StatelessDoWorkTest.TestEntity.class
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
public class StatelessDoWorkTest {
|
||||||
public static final String EXPECTED_ENTITY_NAME = "test";
|
public static final String EXPECTED_ENTITY_NAME = "test";
|
||||||
public static final Integer PERSISTED_TEST_ENTITY_ID = 1;
|
public static final Integer PERSISTED_TEST_ENTITY_ID = 1;
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
|
||||||
return new Class[] { TestEntity.class };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp(SessionFactoryScope scope) {
|
||||||
inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
TestEntity entity = new TestEntity( PERSISTED_TEST_ENTITY_ID, EXPECTED_ENTITY_NAME );
|
TestEntity entity = new TestEntity( PERSISTED_TEST_ENTITY_ID, EXPECTED_ENTITY_NAME );
|
||||||
session.save( entity );
|
session.save( entity );
|
||||||
|
@ -56,9 +58,9 @@ public class StatelessDoWorkTest extends BaseCoreFunctionalTestCase {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@AfterEach
|
||||||
public void tearDown() {
|
public void tearDown(SessionFactoryScope scope) {
|
||||||
inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
session.createQuery( "delete from TestEntity" ).executeUpdate();
|
session.createQuery( "delete from TestEntity" ).executeUpdate();
|
||||||
}
|
}
|
||||||
|
@ -66,9 +68,9 @@ public class StatelessDoWorkTest extends BaseCoreFunctionalTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDoReturningWork() {
|
public void testDoReturningWork(SessionFactoryScope scope) {
|
||||||
String retrievedEntityName;
|
String retrievedEntityName;
|
||||||
try (StatelessSession statelessSession = sessionFactory().openStatelessSession()) {
|
try (StatelessSession statelessSession = scope.getSessionFactory().openStatelessSession()) {
|
||||||
retrievedEntityName = statelessSession.doReturningWork(
|
retrievedEntityName = statelessSession.doReturningWork(
|
||||||
(connection) -> {
|
(connection) -> {
|
||||||
try (PreparedStatement preparedStatement = connection.prepareStatement(
|
try (PreparedStatement preparedStatement = connection.prepareStatement(
|
||||||
|
@ -89,8 +91,8 @@ public class StatelessDoWorkTest extends BaseCoreFunctionalTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDoWork() {
|
public void testDoWork(SessionFactoryScope scope) {
|
||||||
try (StatelessSession statelessSession = sessionFactory().openStatelessSession()) {
|
try (StatelessSession statelessSession = scope.getSessionFactory().openStatelessSession()) {
|
||||||
statelessSession.doWork(
|
statelessSession.doWork(
|
||||||
(connection) -> {
|
(connection) -> {
|
||||||
try (PreparedStatement preparedStatement = connection.prepareStatement(
|
try (PreparedStatement preparedStatement = connection.prepareStatement(
|
||||||
|
@ -101,11 +103,11 @@ public class StatelessDoWorkTest extends BaseCoreFunctionalTestCase {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThatAllTestEntitiesHaveBeenDeleted();
|
assertThatAllTestEntitiesHaveBeenDeleted( scope );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertThatAllTestEntitiesHaveBeenDeleted() {
|
private void assertThatAllTestEntitiesHaveBeenDeleted(SessionFactoryScope scope) {
|
||||||
inTransaction( session -> {
|
scope.inTransaction( session -> {
|
||||||
List results = session.createQuery( "from TestEntity" ).list();
|
List results = session.createQuery( "from TestEntity" ).list();
|
||||||
assertThat( results.size(), is( 0 ) );
|
assertThat( results.size(), is( 0 ) );
|
||||||
} );
|
} );
|
|
@ -0,0 +1,128 @@
|
||||||
|
package org.hibernate.orm.test.stateless;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.StatelessSession;
|
||||||
|
import org.hibernate.Transaction;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||||
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.logger.Triggerable;
|
||||||
|
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.Jpa;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.hibernate.testing.orm.logger.LoggerInspectionExtension;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
@Jpa(
|
||||||
|
annotatedClasses = StatelessSessionConnectionTest.Employee.class,
|
||||||
|
properties = @Setting(name = AvailableSettings.STATEMENT_BATCH_SIZE, value = "10")
|
||||||
|
)
|
||||||
|
public class StatelessSessionConnectionTest {
|
||||||
|
|
||||||
|
final CoreMessageLogger messageLogger = Logger.getMessageLogger(
|
||||||
|
CoreMessageLogger.class,
|
||||||
|
SequenceStyleGenerator.class.getName()
|
||||||
|
);
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
public LoggerInspectionExtension logInspection = LoggerInspectionExtension
|
||||||
|
.builder().setLogger( messageLogger ).build();
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-11732")
|
||||||
|
public void test(EntityManagerFactoryScope scope) {
|
||||||
|
Triggerable triggerable = logInspection.watchForLogMessages( "HHH000352" );
|
||||||
|
triggerable.reset();
|
||||||
|
|
||||||
|
StatelessSession session = scope.getEntityManagerFactory()
|
||||||
|
.unwrap( SessionFactory.class )
|
||||||
|
.openStatelessSession();
|
||||||
|
Transaction tx = session.beginTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Employee employee = new Employee( "1", "2", 1 );
|
||||||
|
employee.setId( 1 );
|
||||||
|
session.insert( employee );
|
||||||
|
|
||||||
|
tx.rollback();
|
||||||
|
}
|
||||||
|
catch (HibernateException e) {
|
||||||
|
if ( tx != null ) {
|
||||||
|
tx.rollback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
session.close();
|
||||||
|
assertFalse( triggerable.wasTriggered() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Employee")
|
||||||
|
public static class Employee {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String firstName;
|
||||||
|
|
||||||
|
private String lastName;
|
||||||
|
|
||||||
|
private int salary;
|
||||||
|
|
||||||
|
public Employee() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Employee(String fname, String lname, int salary) {
|
||||||
|
this.firstName = fname;
|
||||||
|
this.lastName = lname;
|
||||||
|
this.salary = salary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirstName() {
|
||||||
|
return firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstName(String first_name) {
|
||||||
|
this.firstName = first_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastName() {
|
||||||
|
return lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastName(String last_name) {
|
||||||
|
this.lastName = last_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSalary() {
|
||||||
|
return salary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSalary(int salary) {
|
||||||
|
this.salary = salary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.stateless;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.StatelessSession;
|
||||||
|
import org.hibernate.query.NativeQuery;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = StatelessSessionNativeQueryInsertTest.TestEntity.class
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
public class StatelessSessionNativeQueryInsertTest {
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void tearDown(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session ->
|
||||||
|
session.createQuery( "delete from TestEntity" ).executeUpdate()
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-12141")
|
||||||
|
public void testInsertInStatelessSession(SessionFactoryScope scope) {
|
||||||
|
scope.inSession(
|
||||||
|
session ->
|
||||||
|
session.doWork(
|
||||||
|
connection -> {
|
||||||
|
StatelessSession sls = scope.getSessionFactory().openStatelessSession( connection );
|
||||||
|
NativeQuery q = sls.createNativeQuery(
|
||||||
|
"INSERT INTO TEST_ENTITY (ID,SIMPLE_ATTRIBUTE) values (1,'red')" );
|
||||||
|
q.executeUpdate();
|
||||||
|
} )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "TestEntity")
|
||||||
|
@Table(name = "TEST_ENTITY")
|
||||||
|
public static class TestEntity {
|
||||||
|
@Id
|
||||||
|
@Column(name = "ID")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "SIMPLE_ATTRIBUTE")
|
||||||
|
private String simpleAttribute;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stateless;
|
package org.hibernate.orm.test.stateless;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
@ -21,26 +21,42 @@ import org.hibernate.engine.spi.PersistenceContext;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.junit.Test;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrea Boriero
|
* @author Andrea Boriero
|
||||||
*/
|
*/
|
||||||
public class StatelessSessionPersistentContextTest extends BaseCoreFunctionalTestCase {
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
StatelessSessionPersistentContextTest.TestEntity.class,
|
||||||
|
StatelessSessionPersistentContextTest.OtherEntity.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
public class StatelessSessionPersistentContextTest {
|
||||||
|
|
||||||
@Override
|
@AfterEach
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
public void tearDown(SessionFactoryScope scope) {
|
||||||
return new Class[] { TestEntity.class, OtherEntity.class };
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete from TestEntity" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from OtherEntity" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-13672")
|
@TestForIssue(jiraKey = "HHH-13672")
|
||||||
public void testStatelessSessionPersistenceContextIsCleared() {
|
public void testStatelessSessionPersistenceContextIsCleared(SessionFactoryScope scope) {
|
||||||
TestEntity testEntity = new TestEntity();
|
TestEntity testEntity = new TestEntity();
|
||||||
consumeAndCheckPersistenceContextIsClosed(
|
consumeAndCheckPersistenceContextIsClosed(
|
||||||
|
scope,
|
||||||
statelessSession -> {
|
statelessSession -> {
|
||||||
testEntity.setName( "Fab" );
|
testEntity.setName( "Fab" );
|
||||||
OtherEntity otherEntity = new OtherEntity();
|
OtherEntity otherEntity = new OtherEntity();
|
||||||
|
@ -52,12 +68,14 @@ public class StatelessSessionPersistentContextTest extends BaseCoreFunctionalTes
|
||||||
);
|
);
|
||||||
|
|
||||||
consumeAndCheckPersistenceContextIsClosed(
|
consumeAndCheckPersistenceContextIsClosed(
|
||||||
|
scope,
|
||||||
statelessSession -> {
|
statelessSession -> {
|
||||||
statelessSession.get( TestEntity.class, testEntity.getId() );
|
statelessSession.get( TestEntity.class, testEntity.getId() );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
consumeAndCheckPersistenceContextIsClosed(
|
consumeAndCheckPersistenceContextIsClosed(
|
||||||
|
scope,
|
||||||
statelessSession -> {
|
statelessSession -> {
|
||||||
TestEntity p2 = (TestEntity) statelessSession.get( TestEntity.class, testEntity.getId() );
|
TestEntity p2 = (TestEntity) statelessSession.get( TestEntity.class, testEntity.getId() );
|
||||||
p2.setName( "Fabulous" );
|
p2.setName( "Fabulous" );
|
||||||
|
@ -66,6 +84,7 @@ public class StatelessSessionPersistentContextTest extends BaseCoreFunctionalTes
|
||||||
);
|
);
|
||||||
|
|
||||||
consumeAndCheckPersistenceContextIsClosed(
|
consumeAndCheckPersistenceContextIsClosed(
|
||||||
|
scope,
|
||||||
statelessSession -> {
|
statelessSession -> {
|
||||||
TestEntity testEntity1 = (TestEntity) statelessSession.createQuery(
|
TestEntity testEntity1 = (TestEntity) statelessSession.createQuery(
|
||||||
"select p from TestEntity p where id = :id" )
|
"select p from TestEntity p where id = :id" )
|
||||||
|
@ -76,23 +95,25 @@ public class StatelessSessionPersistentContextTest extends BaseCoreFunctionalTes
|
||||||
);
|
);
|
||||||
|
|
||||||
consumeAndCheckPersistenceContextIsClosed(
|
consumeAndCheckPersistenceContextIsClosed(
|
||||||
|
scope,
|
||||||
statelessSession -> {
|
statelessSession -> {
|
||||||
statelessSession.refresh( testEntity );
|
statelessSession.refresh( testEntity );
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
consumeAndCheckPersistenceContextIsClosed(
|
consumeAndCheckPersistenceContextIsClosed(
|
||||||
|
scope,
|
||||||
statelessSession -> {
|
statelessSession -> {
|
||||||
statelessSession.delete( testEntity );
|
statelessSession.delete( testEntity );
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void consumeAndCheckPersistenceContextIsClosed(Consumer<StatelessSession> consumer) {
|
private void consumeAndCheckPersistenceContextIsClosed(
|
||||||
|
SessionFactoryScope scope,
|
||||||
|
Consumer<StatelessSession> consumer) {
|
||||||
Transaction transaction = null;
|
Transaction transaction = null;
|
||||||
StatelessSession statelessSession = sessionFactory().openStatelessSession();
|
StatelessSession statelessSession = scope.getSessionFactory().openStatelessSession();
|
||||||
try {
|
try {
|
||||||
transaction = statelessSession.beginTransaction();
|
transaction = statelessSession.beginTransaction();
|
||||||
consumer.accept( statelessSession );
|
consumer.accept( statelessSession );
|
||||||
|
@ -113,20 +134,20 @@ public class StatelessSessionPersistentContextTest extends BaseCoreFunctionalTes
|
||||||
private void assertThatPersistenContextIsCleared(StatelessSession ss) {
|
private void assertThatPersistenContextIsCleared(StatelessSession ss) {
|
||||||
PersistenceContext persistenceContextInternal = ( (SharedSessionContractImplementor) ss ).getPersistenceContextInternal();
|
PersistenceContext persistenceContextInternal = ( (SharedSessionContractImplementor) ss ).getPersistenceContextInternal();
|
||||||
assertTrue(
|
assertTrue(
|
||||||
"StatelessSession: PersistenceContext has not been cleared",
|
persistenceContextInternal.getEntitiesByKey().isEmpty(),
|
||||||
persistenceContextInternal.getEntitiesByKey().isEmpty()
|
"StatelessSession: PersistenceContext has not been cleared"
|
||||||
);
|
);
|
||||||
assertTrue(
|
assertTrue(
|
||||||
"StatelessSession: PersistenceContext has not been cleared",
|
persistenceContextInternal.managedEntitiesIterator() == Collections.emptyIterator(),
|
||||||
persistenceContextInternal.managedEntitiesIterator() == Collections.emptyIterator()
|
"StatelessSession: PersistenceContext has not been cleared"
|
||||||
);
|
);
|
||||||
assertTrue(
|
assertTrue(
|
||||||
"StatelessSession: PersistenceContext has not been cleared",
|
persistenceContextInternal.getCollectionsByKey().isEmpty(),
|
||||||
persistenceContextInternal.getCollectionsByKey().isEmpty()
|
"StatelessSession: PersistenceContext has not been cleared"
|
||||||
);
|
);
|
||||||
assertTrue(
|
assertTrue(
|
||||||
"StatelessSession: PersistenceContext has not been cleared",
|
persistenceContextInternal.getCollectionsByKey() == Collections.emptyMap(),
|
||||||
persistenceContextInternal.getCollectionsByKey() == Collections.emptyMap()
|
"StatelessSession: PersistenceContext has not been cleared"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.stateless;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.dialect.AbstractHANADialect;
|
||||||
|
import org.hibernate.query.NativeQuery;
|
||||||
|
import org.hibernate.query.Query;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author stliu
|
||||||
|
*/
|
||||||
|
@DomainModel(
|
||||||
|
xmlMappings = "org/hibernate/orm/test/stateless/Contact.hbm.xml"
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
@ServiceRegistry(
|
||||||
|
settings = @Setting(name = Environment.MAX_FETCH_DEPTH, value = "1")
|
||||||
|
)
|
||||||
|
public class StatelessSessionQueryTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SkipForDialect(dialectClass = AbstractHANADialect.class, matchSubTypes = true, reason = " HANA doesn't support tables consisting of only a single auto-generated column")
|
||||||
|
public void testHQL(SessionFactoryScope scope) {
|
||||||
|
scope.inStatelessSession(
|
||||||
|
session ->
|
||||||
|
assertEquals( 1, session.createQuery(
|
||||||
|
"from Contact c join fetch c.org o join fetch c.org.country" )
|
||||||
|
.list().size() )
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-13194")
|
||||||
|
@SkipForDialect(dialectClass = AbstractHANADialect.class, matchSubTypes = true, reason = " HANA doesn't support tables consisting of only a single auto-generated column")
|
||||||
|
public void testNewQueryApis(SessionFactoryScope scope) {
|
||||||
|
|
||||||
|
final String queryString = "from Contact c join fetch c.org o join fetch o.country";
|
||||||
|
|
||||||
|
scope.inStatelessSession(
|
||||||
|
session -> {
|
||||||
|
Query query = session.createQuery( queryString );
|
||||||
|
assertEquals( 1, query.getResultList().size() );
|
||||||
|
|
||||||
|
query = session.getNamedQuery( Contact.class.getName() + ".contacts" );
|
||||||
|
assertEquals( 1, query.getResultList().size() );
|
||||||
|
|
||||||
|
NativeQuery sqlQuery = session.createNativeQuery( "select id from Contact" );
|
||||||
|
assertEquals( 1, sqlQuery.getResultList().size() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List list;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void createData(SessionFactoryScope scope) {
|
||||||
|
list = new ArrayList();
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Country usa = new Country();
|
||||||
|
session.save( usa );
|
||||||
|
list.add( usa );
|
||||||
|
Org disney = new Org();
|
||||||
|
disney.setCountry( usa );
|
||||||
|
session.save( disney );
|
||||||
|
list.add( disney );
|
||||||
|
Contact waltDisney = new Contact();
|
||||||
|
waltDisney.setOrg( disney );
|
||||||
|
session.save( waltDisney );
|
||||||
|
list.add( waltDisney );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void cleanData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
for ( Object obj : list ) {
|
||||||
|
session.delete( obj );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.stateless;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import javax.persistence.criteria.CriteriaBuilder;
|
||||||
|
import javax.persistence.criteria.CriteriaQuery;
|
||||||
|
|
||||||
|
import org.hibernate.ScrollMode;
|
||||||
|
import org.hibernate.ScrollableResults;
|
||||||
|
import org.hibernate.Transaction;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gavin King
|
||||||
|
*/
|
||||||
|
@DomainModel(
|
||||||
|
xmlMappings = "org/hibernate/orm/test/stateless/Document.hbm.xml"
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
public class StatelessSessionTest {
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void tearDown(SessionFactoryScope scope){
|
||||||
|
scope.inTransaction(
|
||||||
|
session ->
|
||||||
|
session.createQuery( "delete from Document" ).executeUpdate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateUpdateReadDelete(SessionFactoryScope scope) {
|
||||||
|
scope.inStatelessSession(
|
||||||
|
statelessSession -> {
|
||||||
|
try {
|
||||||
|
Transaction tx = statelessSession.beginTransaction();
|
||||||
|
Document doc = new Document( "blah blah blah", "Blahs" );
|
||||||
|
statelessSession.insert( doc );
|
||||||
|
assertNotNull( doc.getName() );
|
||||||
|
Date initVersion = doc.getLastModified();
|
||||||
|
assertNotNull( initVersion );
|
||||||
|
tx.commit();
|
||||||
|
|
||||||
|
tx = statelessSession.beginTransaction();
|
||||||
|
doc.setText( "blah blah blah .... blah" );
|
||||||
|
statelessSession.update( doc );
|
||||||
|
assertNotNull( doc.getLastModified() );
|
||||||
|
assertNotSame( doc.getLastModified(), initVersion );
|
||||||
|
tx.commit();
|
||||||
|
|
||||||
|
tx = statelessSession.beginTransaction();
|
||||||
|
doc.setText( "blah blah blah .... blah blay" );
|
||||||
|
statelessSession.update( doc );
|
||||||
|
tx.commit();
|
||||||
|
|
||||||
|
Document doc2 = (Document) statelessSession.get( Document.class.getName(), "Blahs" );
|
||||||
|
assertEquals( "Blahs", doc2.getName() );
|
||||||
|
assertEquals( doc.getText(), doc2.getText() );
|
||||||
|
|
||||||
|
doc2 = (Document) statelessSession.createQuery( "from Document where text is not null" )
|
||||||
|
.uniqueResult();
|
||||||
|
assertEquals( "Blahs", doc2.getName() );
|
||||||
|
assertEquals( doc.getText(), doc2.getText() );
|
||||||
|
|
||||||
|
ScrollableResults sr = statelessSession.createQuery( "from Document where text is not null" )
|
||||||
|
.scroll( ScrollMode.FORWARD_ONLY );
|
||||||
|
sr.next();
|
||||||
|
doc2 = (Document) sr.get();
|
||||||
|
sr.close();
|
||||||
|
assertEquals( "Blahs", doc2.getName() );
|
||||||
|
assertEquals( doc.getText(), doc2.getText() );
|
||||||
|
|
||||||
|
doc2 = (Document) statelessSession.createSQLQuery( "select * from Document" )
|
||||||
|
.addEntity( Document.class )
|
||||||
|
.uniqueResult();
|
||||||
|
assertEquals( "Blahs", doc2.getName() );
|
||||||
|
assertEquals( doc.getText(), doc2.getText() );
|
||||||
|
|
||||||
|
|
||||||
|
CriteriaBuilder criteriaBuilder = statelessSession.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Document> criteria = criteriaBuilder.createQuery( Document.class );
|
||||||
|
criteria.from( Document.class );
|
||||||
|
doc2 = statelessSession.createQuery( criteria ).uniqueResult();
|
||||||
|
assertEquals( "Blahs", doc2.getName() );
|
||||||
|
assertEquals( doc.getText(), doc2.getText() );
|
||||||
|
|
||||||
|
criteria = criteriaBuilder.createQuery( Document.class );
|
||||||
|
criteria.from( Document.class );
|
||||||
|
|
||||||
|
sr = statelessSession.createQuery( criteria ).scroll( ScrollMode.FORWARD_ONLY );
|
||||||
|
sr.next();
|
||||||
|
doc2 = (Document) sr.get();
|
||||||
|
sr.close();
|
||||||
|
assertEquals( "Blahs", doc2.getName() );
|
||||||
|
assertEquals( doc.getText(), doc2.getText() );
|
||||||
|
|
||||||
|
tx = statelessSession.beginTransaction();
|
||||||
|
statelessSession.delete( doc );
|
||||||
|
tx.commit();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
if ( statelessSession.getTransaction().isActive() ) {
|
||||||
|
statelessSession.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHqlBulk(SessionFactoryScope scope) {
|
||||||
|
scope.inStatelessSession(
|
||||||
|
statelessSession -> {
|
||||||
|
try {
|
||||||
|
Transaction tx = statelessSession.beginTransaction();
|
||||||
|
Document doc = new Document( "blah blah blah", "Blahs" );
|
||||||
|
statelessSession.insert( doc );
|
||||||
|
Paper paper = new Paper();
|
||||||
|
paper.setColor( "White" );
|
||||||
|
statelessSession.insert( paper );
|
||||||
|
tx.commit();
|
||||||
|
|
||||||
|
tx = statelessSession.beginTransaction();
|
||||||
|
int count = statelessSession.createQuery(
|
||||||
|
"update Document set name = :newName where name = :oldName" )
|
||||||
|
.setParameter( "newName", "Foos" )
|
||||||
|
.setParameter( "oldName", "Blahs" )
|
||||||
|
.executeUpdate();
|
||||||
|
assertEquals( 1, count, "hql-update on stateless session" );
|
||||||
|
count = statelessSession.createQuery( "update Paper set color = :newColor" )
|
||||||
|
.setParameter( "newColor", "Goldenrod" )
|
||||||
|
.executeUpdate();
|
||||||
|
assertEquals( 1, count, "hql-update on stateless session" );
|
||||||
|
tx.commit();
|
||||||
|
|
||||||
|
tx = statelessSession.beginTransaction();
|
||||||
|
count = statelessSession.createQuery( "delete Document" ).executeUpdate();
|
||||||
|
assertEquals( 1, count, "hql-delete on stateless session" );
|
||||||
|
count = statelessSession.createQuery( "delete Paper" ).executeUpdate();
|
||||||
|
assertEquals( 1, count, "hql-delete on stateless session" );
|
||||||
|
tx.commit();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( statelessSession.getTransaction().isActive() ) {
|
||||||
|
statelessSession.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInitId(SessionFactoryScope scope) {
|
||||||
|
scope.inStatelessSession(
|
||||||
|
statelessSession -> {
|
||||||
|
try {
|
||||||
|
Transaction tx = statelessSession.beginTransaction();
|
||||||
|
Paper paper = new Paper();
|
||||||
|
paper.setColor( "White" );
|
||||||
|
statelessSession.insert( paper );
|
||||||
|
assertNotNull( paper.getId() );
|
||||||
|
tx.commit();
|
||||||
|
|
||||||
|
tx = statelessSession.beginTransaction();
|
||||||
|
statelessSession.delete( statelessSession.get( Paper.class, paper.getId() ) );
|
||||||
|
tx.commit();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( statelessSession.getTransaction().isActive() ) {
|
||||||
|
statelessSession.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRefresh(SessionFactoryScope scope) {
|
||||||
|
Paper paper = new Paper();
|
||||||
|
scope.inStatelessTransaction(
|
||||||
|
statelessSession -> {
|
||||||
|
paper.setColor( "whtie" );
|
||||||
|
statelessSession.insert( paper );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inStatelessTransaction(
|
||||||
|
statelessSession -> {
|
||||||
|
Paper p2 = (Paper) statelessSession.get( Paper.class, paper.getId() );
|
||||||
|
p2.setColor( "White" );
|
||||||
|
statelessSession.update( p2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inStatelessTransaction(
|
||||||
|
statelessSession -> {
|
||||||
|
assertEquals( "whtie", paper.getColor() );
|
||||||
|
statelessSession.refresh( paper );
|
||||||
|
assertEquals( "White", paper.getColor() );
|
||||||
|
statelessSession.delete( paper );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||||
|
|
||||||
<hibernate-mapping package="org.hibernate.test.stateless.fetching">
|
<hibernate-mapping package="org.hibernate.orm.test.stateless.fetching">
|
||||||
|
|
||||||
<class name="User">
|
<class name="User">
|
||||||
<id name="id" type="long">
|
<id name="id" type="long">
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stateless.fetching;
|
package org.hibernate.orm.test.stateless.fetching;
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.FetchType;
|
import javax.persistence.FetchType;
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stateless.fetching;
|
package org.hibernate.orm.test.stateless.fetching;
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.FetchType;
|
import javax.persistence.FetchType;
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stateless.fetching;
|
package org.hibernate.orm.test.stateless.fetching;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -0,0 +1,239 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.stateless.fetching;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.ScrollMode;
|
||||||
|
import org.hibernate.ScrollableResults;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.dialect.DB2Dialect;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.query.Query;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = { Producer.class, Product.class, Vendor.class },
|
||||||
|
xmlMappings = "org/hibernate/orm/test/stateless/fetching/Mappings.hbm.xml"
|
||||||
|
|
||||||
|
)
|
||||||
|
@ServiceRegistry(
|
||||||
|
settings = @Setting(name = AvailableSettings.PHYSICAL_NAMING_STRATEGY, value = "org.hibernate.orm.test.stateless.fetching.TestingNamingStrategy")
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
public class StatelessSessionFetchingTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicFetch(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Date now = new Date();
|
||||||
|
User me = new User( "me" );
|
||||||
|
User you = new User( "you" );
|
||||||
|
Resource yourClock = new Resource( "clock", you );
|
||||||
|
Task task = new Task( me, "clean", yourClock, now ); // :)
|
||||||
|
session.save( me );
|
||||||
|
session.save( you );
|
||||||
|
session.save( yourClock );
|
||||||
|
session.save( task );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inStatelessTransaction(
|
||||||
|
session -> {
|
||||||
|
Task taskRef = (Task) session.createQuery( "from Task t join fetch t.resource join fetch t.user" )
|
||||||
|
.uniqueResult();
|
||||||
|
assertNotNull( taskRef );
|
||||||
|
assertTrue( Hibernate.isInitialized( taskRef ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( taskRef.getUser() ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( taskRef.getResource() ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( taskRef.getResource().getOwner() ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicFetchScroll(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Date now = new Date();
|
||||||
|
|
||||||
|
User me = new User( "me" );
|
||||||
|
User you = new User( "you" );
|
||||||
|
Resource yourClock = new Resource( "clock", you );
|
||||||
|
Task task = new Task( me, "clean", yourClock, now ); // :)
|
||||||
|
|
||||||
|
session.save( me );
|
||||||
|
session.save( you );
|
||||||
|
session.save( yourClock );
|
||||||
|
session.save( task );
|
||||||
|
|
||||||
|
User u3 = new User( "U3" );
|
||||||
|
User u4 = new User( "U4" );
|
||||||
|
Resource it = new Resource( "it", u4 );
|
||||||
|
Task task2 = new Task( u3, "beat", it, now ); // :))
|
||||||
|
|
||||||
|
session.save( u3 );
|
||||||
|
session.save( u4 );
|
||||||
|
session.save( it );
|
||||||
|
session.save( task2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inStatelessTransaction(
|
||||||
|
session -> {
|
||||||
|
final Query query = session.createQuery( "from Task t join fetch t.resource join fetch t.user" );
|
||||||
|
final ScrollableResults scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
|
||||||
|
while ( scrollableResults.next() ) {
|
||||||
|
Task taskRef = (Task) scrollableResults.get();
|
||||||
|
assertTrue( Hibernate.isInitialized( taskRef ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( taskRef.getUser() ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( taskRef.getResource() ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( taskRef.getResource().getOwner() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicFetchScrollSession(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Date now = new Date();
|
||||||
|
|
||||||
|
User me = new User( "me" );
|
||||||
|
User you = new User( "you" );
|
||||||
|
Resource yourClock = new Resource( "clock", you );
|
||||||
|
Task task = new Task( me, "clean", yourClock, now ); // :)
|
||||||
|
|
||||||
|
session.save( me );
|
||||||
|
session.save( you );
|
||||||
|
session.save( yourClock );
|
||||||
|
session.save( task );
|
||||||
|
|
||||||
|
User u3 = new User( "U3" );
|
||||||
|
User u4 = new User( "U4" );
|
||||||
|
Resource it = new Resource( "it", u4 );
|
||||||
|
Task task2 = new Task( u3, "beat", it, now ); // :))
|
||||||
|
|
||||||
|
session.save( u3 );
|
||||||
|
session.save( u4 );
|
||||||
|
session.save( it );
|
||||||
|
session.save( task2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inStatelessTransaction(
|
||||||
|
session -> {
|
||||||
|
final Query query = session.createQuery( "from Task t join fetch t.resource join fetch t.user" );
|
||||||
|
final ScrollableResults scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
|
||||||
|
while ( scrollableResults.next() ) {
|
||||||
|
Task taskRef = (Task) scrollableResults.get();
|
||||||
|
assertTrue( Hibernate.isInitialized( taskRef ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( taskRef.getUser() ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( taskRef.getResource() ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( taskRef.getResource().getOwner() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicFetchCollectionScroll(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
Producer p1 = new Producer( 1, "Acme" );
|
||||||
|
Producer p2 = new Producer( 2, "ABC" );
|
||||||
|
|
||||||
|
session.save( p1 );
|
||||||
|
session.save( p2 );
|
||||||
|
|
||||||
|
Vendor v1 = new Vendor( 1, "v1" );
|
||||||
|
Vendor v2 = new Vendor( 2, "v2" );
|
||||||
|
|
||||||
|
session.save( v1 );
|
||||||
|
session.save( v2 );
|
||||||
|
|
||||||
|
final Product product1 = new Product( 1, "123", v1, p1 );
|
||||||
|
final Product product2 = new Product( 2, "456", v1, p1 );
|
||||||
|
final Product product3 = new Product( 3, "789", v1, p2 );
|
||||||
|
|
||||||
|
session.save( product1 );
|
||||||
|
session.save( product2 );
|
||||||
|
session.save( product3 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inStatelessTransaction(
|
||||||
|
session -> {
|
||||||
|
final Query query = session.createQuery( "select p from Producer p join fetch p.products" );
|
||||||
|
final ScrollableResults scrollableResults = getScrollableResults( query,
|
||||||
|
scope.getSessionFactory()
|
||||||
|
.getJdbcServices()
|
||||||
|
.getDialect()
|
||||||
|
);
|
||||||
|
|
||||||
|
while ( scrollableResults.next() ) {
|
||||||
|
Producer producer = (Producer) scrollableResults.get();
|
||||||
|
assertTrue( Hibernate.isInitialized( producer ) );
|
||||||
|
assertTrue( Hibernate.isInitialized( producer.getProducts() ) );
|
||||||
|
|
||||||
|
for ( Product product : producer.getProducts() ) {
|
||||||
|
assertTrue( Hibernate.isInitialized( product ) );
|
||||||
|
assertFalse( Hibernate.isInitialized( product.getVendor() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScrollableResults getScrollableResults(Query query, Dialect dialect) {
|
||||||
|
if ( dialect instanceof DB2Dialect ) {
|
||||||
|
/*
|
||||||
|
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
|
||||||
|
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
|
||||||
|
set type of TYPE_FORWARD_ONLY and db2 does not support it.
|
||||||
|
*/
|
||||||
|
return query.scroll( ScrollMode.SCROLL_INSENSITIVE );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return query.scroll( ScrollMode.FORWARD_ONLY );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void cleanup(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete Task" ).executeUpdate();
|
||||||
|
session.createQuery( "delete Resource" ).executeUpdate();
|
||||||
|
session.createQuery( "delete User" ).executeUpdate();
|
||||||
|
|
||||||
|
session.createQuery( "delete Product" ).executeUpdate();
|
||||||
|
session.createQuery( "delete Producer" ).executeUpdate();
|
||||||
|
session.createQuery( "delete Vendor" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stateless.fetching;
|
package org.hibernate.orm.test.stateless.fetching;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.hibernate.orm.test.stateless.fetching;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.hibernate.boot.model.naming.Identifier;
|
||||||
|
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
|
||||||
|
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||||
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
|
||||||
|
public class TestingNamingStrategy extends PhysicalNamingStrategyStandardImpl {
|
||||||
|
private final String prefix = determineUniquePrefix();
|
||||||
|
|
||||||
|
protected String applyPrefix(String baseTableName) {
|
||||||
|
String prefixed = prefix + '_' + baseTableName;
|
||||||
|
return prefixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironment) {
|
||||||
|
return jdbcEnvironment.getIdentifierHelper().toIdentifier( applyPrefix( name.getText() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private String determineUniquePrefix() {
|
||||||
|
return StringHelper.collapseQualifier( getClass().getName(), false ).toUpperCase( Locale.ROOT );
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stateless.fetching;
|
package org.hibernate.orm.test.stateless.fetching;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stateless.fetching;
|
package org.hibernate.orm.test.stateless.fetching;
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.FetchType;
|
import javax.persistence.FetchType;
|
|
@ -9,7 +9,7 @@
|
||||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||||
|
|
||||||
<hibernate-mapping package="org.hibernate.test.stateless.insert">
|
<hibernate-mapping package="org.hibernate.orm.test.stateless.insert">
|
||||||
|
|
||||||
<class name="Message">
|
<class name="Message">
|
||||||
<cache usage="read-write"/>
|
<cache usage="read-write"/>
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stateless.insert;
|
package org.hibernate.orm.test.stateless.insert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author mukhanov@gmail.com
|
* @author mukhanov@gmail.com
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.stateless.insert;
|
package org.hibernate.orm.test.stateless.insert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author mukhanov@gmail.com
|
* @author mukhanov@gmail.com
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.stateless.insert;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author mukhanov@gmail.com
|
||||||
|
*/
|
||||||
|
@DomainModel(
|
||||||
|
xmlMappings = "org/hibernate/orm/test/stateless/insert/Mappings.hbm.xml"
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
public class StatelessSessionInsertTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInsertWithForeignKey(SessionFactoryScope scope) {
|
||||||
|
Message msg = new Message();
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
final String messageId = "message_id";
|
||||||
|
msg.setId( messageId );
|
||||||
|
msg.setContent( "message_content" );
|
||||||
|
msg.setSubject( "message_subject" );
|
||||||
|
session.save( msg );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inStatelessTransaction(
|
||||||
|
statelessSession -> {
|
||||||
|
MessageRecipient signature = new MessageRecipient();
|
||||||
|
signature.setId( "recipient" );
|
||||||
|
signature.setEmail( "recipient@hibernate.org" );
|
||||||
|
signature.setMessage( msg );
|
||||||
|
statelessSession.insert( signature );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void cleanup(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete MessageRecipient" ).executeUpdate();
|
||||||
|
session.createQuery( "delete Message" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,126 +0,0 @@
|
||||||
package org.hibernate.test.stateless;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.Id;
|
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.hibernate.StatelessSession;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl;
|
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
|
||||||
import org.hibernate.internal.SessionImpl;
|
|
||||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
|
||||||
import org.hibernate.testing.logger.LoggerInspectionRule;
|
|
||||||
import org.hibernate.testing.logger.Triggerable;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
|
||||||
import static org.hamcrest.core.Is.is;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Vlad Mihalcea
|
|
||||||
*/
|
|
||||||
public class StatelessSessionConnectionTest extends BaseEntityManagerFunctionalTestCase {
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public LoggerInspectionRule logInspection = new LoggerInspectionRule( Logger.getMessageLogger( CoreMessageLogger.class, AbstractBatchImpl.class.getName() ) );
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
|
||||||
return new Class<?>[] {
|
|
||||||
Employee.class
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void addConfigOptions(Map options) {
|
|
||||||
options.put( AvailableSettings.STATEMENT_BATCH_SIZE, 10 );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestForIssue( jiraKey = "HHH-11732" )
|
|
||||||
public void test() {
|
|
||||||
Triggerable triggerable = logInspection.watchForLogMessages( "HHH000352" );
|
|
||||||
triggerable.reset();
|
|
||||||
|
|
||||||
StatelessSession session = entityManagerFactory().unwrap( SessionFactory.class ).openStatelessSession();
|
|
||||||
Transaction tx = session.beginTransaction();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Employee employee = new Employee( "1", "2", 1 );
|
|
||||||
employee.setId( 1 );
|
|
||||||
session.insert( employee );
|
|
||||||
|
|
||||||
tx.rollback();
|
|
||||||
}
|
|
||||||
catch (HibernateException e) {
|
|
||||||
if ( tx != null ) {
|
|
||||||
tx.rollback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
session.close();
|
|
||||||
assertFalse( triggerable.wasTriggered() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "Employee")
|
|
||||||
public static class Employee {
|
|
||||||
@Id
|
|
||||||
private Integer id;
|
|
||||||
|
|
||||||
private String firstName;
|
|
||||||
|
|
||||||
private String lastName;
|
|
||||||
|
|
||||||
private int salary;
|
|
||||||
|
|
||||||
public Employee() {}
|
|
||||||
|
|
||||||
public Employee(String fname, String lname, int salary) {
|
|
||||||
this.firstName = fname;
|
|
||||||
this.lastName = lname;
|
|
||||||
this.salary = salary;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId( Integer id ) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFirstName() {
|
|
||||||
return firstName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFirstName( String first_name ) {
|
|
||||||
this.firstName = first_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLastName() {
|
|
||||||
return lastName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastName( String last_name ) {
|
|
||||||
this.lastName = last_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSalary() {
|
|
||||||
return salary;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSalary( int salary ) {
|
|
||||||
this.salary = salary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.test.stateless;
|
|
||||||
|
|
||||||
import javax.persistence.Column;
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.Id;
|
|
||||||
import javax.persistence.Table;
|
|
||||||
|
|
||||||
import org.hibernate.StatelessSession;
|
|
||||||
import org.hibernate.query.NativeQuery;
|
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrea Boriero
|
|
||||||
*/
|
|
||||||
public class StatelessSessionNativeQueryInsertTest extends BaseCoreFunctionalTestCase {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
|
||||||
return new Class[] { TestEntity.class };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestForIssue(jiraKey = "HHH-12141")
|
|
||||||
public void testInsertInStatelessSession() throws Exception {
|
|
||||||
doInHibernate( this::sessionFactory, session -> {
|
|
||||||
session.doWork( connection -> {
|
|
||||||
StatelessSession sls = sessionFactory().openStatelessSession( connection );
|
|
||||||
NativeQuery q = sls.createNativeQuery(
|
|
||||||
"INSERT INTO TEST_ENTITY (ID,SIMPLE_ATTRIBUTE) values (1,'red')" );
|
|
||||||
q.executeUpdate();
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
@Table(name = "TEST_ENTITY")
|
|
||||||
public static class TestEntity {
|
|
||||||
@Id
|
|
||||||
@Column(name = "ID")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Column(name = "SIMPLE_ATTRIBUTE")
|
|
||||||
private String simpleAttribute;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.test.stateless;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.hibernate.FetchMode;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.StatelessSession;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
import org.hibernate.cfg.Environment;
|
|
||||||
import org.hibernate.dialect.AbstractHANADialect;
|
|
||||||
import org.hibernate.query.NativeQuery;
|
|
||||||
|
|
||||||
import org.hibernate.testing.SkipForDialect;
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author stliu
|
|
||||||
*/
|
|
||||||
public class StatelessSessionQueryTest extends BaseCoreFunctionalTestCase {
|
|
||||||
@Override
|
|
||||||
public void configure( Configuration cfg ) {
|
|
||||||
super.configure( cfg );
|
|
||||||
cfg.setProperty( Environment.MAX_FETCH_DEPTH, "1" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getMappings() {
|
|
||||||
return new String[] { "stateless/Contact.hbm.xml" };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@SkipForDialect(value = AbstractHANADialect.class, comment = " HANA doesn't support tables consisting of only a single auto-generated column")
|
|
||||||
public void testHQL() {
|
|
||||||
TestData testData=new TestData();
|
|
||||||
testData.createData();
|
|
||||||
StatelessSession s = sessionFactory().openStatelessSession();
|
|
||||||
assertEquals( 1, s.createQuery( "from Contact c join fetch c.org o join fetch c.org.country" )
|
|
||||||
.list().size() );
|
|
||||||
s.close();
|
|
||||||
testData.cleanData();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestForIssue( jiraKey = "HHH-13194")
|
|
||||||
@SkipForDialect(value = AbstractHANADialect.class, comment = " HANA doesn't support tables consisting of only a single auto-generated column")
|
|
||||||
public void testNewQueryApis() {
|
|
||||||
TestData testData=new TestData();
|
|
||||||
testData.createData();
|
|
||||||
|
|
||||||
final String queryString = "from Contact c join fetch c.org o join fetch o.country";
|
|
||||||
StatelessSession s = sessionFactory().openStatelessSession();
|
|
||||||
|
|
||||||
org.hibernate.query.Query query = s.createQuery( queryString );
|
|
||||||
assertEquals( 1, query.getResultList().size() );
|
|
||||||
|
|
||||||
query = s.getNamedQuery( Contact.class.getName() + ".contacts" );
|
|
||||||
assertEquals( 1, query.getResultList().size() );
|
|
||||||
|
|
||||||
org.hibernate.query.NativeQuery sqlQuery = s.createNativeQuery( "select id from Contact" );
|
|
||||||
assertEquals( 1, sqlQuery.getResultList().size() );
|
|
||||||
|
|
||||||
s.close();
|
|
||||||
testData.cleanData();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestData{
|
|
||||||
List list = new ArrayList();
|
|
||||||
public void createData(){
|
|
||||||
Session session = openSession();
|
|
||||||
Transaction tx = session.beginTransaction();
|
|
||||||
Country usa = new Country();
|
|
||||||
session.save( usa );
|
|
||||||
list.add( usa );
|
|
||||||
Org disney = new Org();
|
|
||||||
disney.setCountry( usa );
|
|
||||||
session.save( disney );
|
|
||||||
list.add( disney );
|
|
||||||
Contact waltDisney = new Contact();
|
|
||||||
waltDisney.setOrg( disney );
|
|
||||||
session.save( waltDisney );
|
|
||||||
list.add( waltDisney );
|
|
||||||
tx.commit();
|
|
||||||
session.close();
|
|
||||||
}
|
|
||||||
public void cleanData(){
|
|
||||||
Session session = openSession();
|
|
||||||
Transaction tx = session.beginTransaction();
|
|
||||||
for(Object obj: list){
|
|
||||||
session.delete( obj );
|
|
||||||
}
|
|
||||||
tx.commit();
|
|
||||||
session.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,187 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.test.stateless;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import javax.persistence.criteria.CriteriaBuilder;
|
|
||||||
import javax.persistence.criteria.CriteriaQuery;
|
|
||||||
|
|
||||||
import org.hibernate.ScrollMode;
|
|
||||||
import org.hibernate.ScrollableResults;
|
|
||||||
import org.hibernate.StatelessSession;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertNotSame;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Gavin King
|
|
||||||
*/
|
|
||||||
public class StatelessSessionTest extends BaseCoreFunctionalTestCase {
|
|
||||||
public String[] getMappings() {
|
|
||||||
return new String[] { "stateless/Document.hbm.xml" };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateUpdateReadDelete() {
|
|
||||||
try (StatelessSession ss = sessionFactory().openStatelessSession()) {
|
|
||||||
try {
|
|
||||||
Transaction tx = ss.beginTransaction();
|
|
||||||
Document doc = new Document( "blah blah blah", "Blahs" );
|
|
||||||
ss.insert( doc );
|
|
||||||
assertNotNull( doc.getName() );
|
|
||||||
Date initVersion = doc.getLastModified();
|
|
||||||
assertNotNull( initVersion );
|
|
||||||
tx.commit();
|
|
||||||
|
|
||||||
tx = ss.beginTransaction();
|
|
||||||
doc.setText( "blah blah blah .... blah" );
|
|
||||||
ss.update( doc );
|
|
||||||
assertNotNull( doc.getLastModified() );
|
|
||||||
assertNotSame( doc.getLastModified(), initVersion );
|
|
||||||
tx.commit();
|
|
||||||
|
|
||||||
tx = ss.beginTransaction();
|
|
||||||
doc.setText( "blah blah blah .... blah blay" );
|
|
||||||
ss.update( doc );
|
|
||||||
tx.commit();
|
|
||||||
|
|
||||||
Document doc2 = (Document) ss.get( Document.class.getName(), "Blahs" );
|
|
||||||
assertEquals( "Blahs", doc2.getName() );
|
|
||||||
assertEquals( doc.getText(), doc2.getText() );
|
|
||||||
|
|
||||||
doc2 = (Document) ss.createQuery( "from Document where text is not null" ).uniqueResult();
|
|
||||||
assertEquals( "Blahs", doc2.getName() );
|
|
||||||
assertEquals( doc.getText(), doc2.getText() );
|
|
||||||
|
|
||||||
ScrollableResults sr = ss.createQuery( "from Document where text is not null" )
|
|
||||||
.scroll( ScrollMode.FORWARD_ONLY );
|
|
||||||
sr.next();
|
|
||||||
doc2 = (Document) sr.get();
|
|
||||||
sr.close();
|
|
||||||
assertEquals( "Blahs", doc2.getName() );
|
|
||||||
assertEquals( doc.getText(), doc2.getText() );
|
|
||||||
|
|
||||||
doc2 = (Document) ss.createSQLQuery( "select * from Document" )
|
|
||||||
.addEntity( Document.class )
|
|
||||||
.uniqueResult();
|
|
||||||
assertEquals( "Blahs", doc2.getName() );
|
|
||||||
assertEquals( doc.getText(), doc2.getText() );
|
|
||||||
|
|
||||||
|
|
||||||
CriteriaBuilder criteriaBuilder = ss.getCriteriaBuilder();
|
|
||||||
CriteriaQuery<Document> criteria = criteriaBuilder.createQuery( Document.class );
|
|
||||||
criteria.from( Document.class );
|
|
||||||
doc2 = ss.createQuery( criteria ).uniqueResult();
|
|
||||||
assertEquals( "Blahs", doc2.getName() );
|
|
||||||
assertEquals( doc.getText(), doc2.getText() );
|
|
||||||
|
|
||||||
criteria = criteriaBuilder.createQuery( Document.class );
|
|
||||||
criteria.from( Document.class );
|
|
||||||
|
|
||||||
sr = ss.createQuery( criteria ).scroll( ScrollMode.FORWARD_ONLY );
|
|
||||||
sr.next();
|
|
||||||
doc2 = (Document) sr.get();
|
|
||||||
sr.close();
|
|
||||||
assertEquals( "Blahs", doc2.getName() );
|
|
||||||
assertEquals( doc.getText(), doc2.getText() );
|
|
||||||
|
|
||||||
tx = ss.beginTransaction();
|
|
||||||
ss.delete( doc );
|
|
||||||
tx.commit();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
if ( ss.getTransaction().isActive() ) {
|
|
||||||
ss.getTransaction().rollback();
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHqlBulk() {
|
|
||||||
StatelessSession ss = sessionFactory().openStatelessSession();
|
|
||||||
Transaction tx = ss.beginTransaction();
|
|
||||||
Document doc = new Document("blah blah blah", "Blahs");
|
|
||||||
ss.insert(doc);
|
|
||||||
Paper paper = new Paper();
|
|
||||||
paper.setColor( "White" );
|
|
||||||
ss.insert(paper);
|
|
||||||
tx.commit();
|
|
||||||
|
|
||||||
tx = ss.beginTransaction();
|
|
||||||
int count = ss.createQuery( "update Document set name = :newName where name = :oldName" )
|
|
||||||
.setParameter( "newName", "Foos" )
|
|
||||||
.setParameter( "oldName", "Blahs" )
|
|
||||||
.executeUpdate();
|
|
||||||
assertEquals( "hql-update on stateless session", 1, count );
|
|
||||||
count = ss.createQuery( "update Paper set color = :newColor" )
|
|
||||||
.setParameter( "newColor", "Goldenrod" )
|
|
||||||
.executeUpdate();
|
|
||||||
assertEquals( "hql-update on stateless session", 1, count );
|
|
||||||
tx.commit();
|
|
||||||
|
|
||||||
tx = ss.beginTransaction();
|
|
||||||
count = ss.createQuery( "delete Document" ).executeUpdate();
|
|
||||||
assertEquals( "hql-delete on stateless session", 1, count );
|
|
||||||
count = ss.createQuery( "delete Paper" ).executeUpdate();
|
|
||||||
assertEquals( "hql-delete on stateless session", 1, count );
|
|
||||||
tx.commit();
|
|
||||||
ss.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInitId() {
|
|
||||||
StatelessSession ss = sessionFactory().openStatelessSession();
|
|
||||||
Transaction tx = ss.beginTransaction();
|
|
||||||
Paper paper = new Paper();
|
|
||||||
paper.setColor( "White" );
|
|
||||||
ss.insert(paper);
|
|
||||||
assertNotNull( paper.getId() );
|
|
||||||
tx.commit();
|
|
||||||
|
|
||||||
tx = ss.beginTransaction();
|
|
||||||
ss.delete( ss.get( Paper.class, paper.getId() ) );
|
|
||||||
tx.commit();
|
|
||||||
ss.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRefresh() {
|
|
||||||
StatelessSession ss = sessionFactory().openStatelessSession();
|
|
||||||
Transaction tx = ss.beginTransaction();
|
|
||||||
Paper paper = new Paper();
|
|
||||||
paper.setColor( "whtie" );
|
|
||||||
ss.insert( paper );
|
|
||||||
tx.commit();
|
|
||||||
ss.close();
|
|
||||||
|
|
||||||
ss = sessionFactory().openStatelessSession();
|
|
||||||
tx = ss.beginTransaction();
|
|
||||||
Paper p2 = ( Paper ) ss.get( Paper.class, paper.getId() );
|
|
||||||
p2.setColor( "White" );
|
|
||||||
ss.update( p2 );
|
|
||||||
tx.commit();
|
|
||||||
ss.close();
|
|
||||||
|
|
||||||
ss = sessionFactory().openStatelessSession();
|
|
||||||
tx = ss.beginTransaction();
|
|
||||||
assertEquals( "whtie", paper.getColor() );
|
|
||||||
ss.refresh( paper );
|
|
||||||
assertEquals( "White", paper.getColor() );
|
|
||||||
ss.delete( paper );
|
|
||||||
tx.commit();
|
|
||||||
ss.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,276 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.test.stateless.fetching;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import org.hibernate.Hibernate;
|
|
||||||
import org.hibernate.ScrollMode;
|
|
||||||
import org.hibernate.ScrollableResults;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.StatelessSession;
|
|
||||||
import org.hibernate.boot.model.naming.Identifier;
|
|
||||||
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
|
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
import org.hibernate.dialect.DB2Dialect;
|
|
||||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
|
||||||
import org.hibernate.internal.util.StringHelper;
|
|
||||||
import org.hibernate.query.Query;
|
|
||||||
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Steve Ebersole
|
|
||||||
*/
|
|
||||||
public class StatelessSessionFetchingTest extends BaseCoreFunctionalTestCase {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getMappings() {
|
|
||||||
return new String[] { "stateless/fetching/Mappings.hbm.xml" };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
|
||||||
return new Class[] { Producer.class, Product.class, Vendor.class };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configure(Configuration cfg) {
|
|
||||||
super.configure( cfg );
|
|
||||||
cfg.setPhysicalNamingStrategy( new TestingNamingStrategy() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestingNamingStrategy extends PhysicalNamingStrategyStandardImpl {
|
|
||||||
private final String prefix = determineUniquePrefix();
|
|
||||||
|
|
||||||
protected String applyPrefix(String baseTableName) {
|
|
||||||
String prefixed = prefix + '_' + baseTableName;
|
|
||||||
log.debug( "prefixed table name : " + baseTableName + " -> " + prefixed );
|
|
||||||
return prefixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironment) {
|
|
||||||
return jdbcEnvironment.getIdentifierHelper().toIdentifier( applyPrefix( name.getText() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
private String determineUniquePrefix() {
|
|
||||||
return StringHelper.collapseQualifier( getClass().getName(), false ).toUpperCase( Locale.ROOT );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDynamicFetch() {
|
|
||||||
Session s = openSession();
|
|
||||||
s.beginTransaction();
|
|
||||||
Date now = new Date();
|
|
||||||
User me = new User( "me" );
|
|
||||||
User you = new User( "you" );
|
|
||||||
Resource yourClock = new Resource( "clock", you );
|
|
||||||
Task task = new Task( me, "clean", yourClock, now ); // :)
|
|
||||||
s.save( me );
|
|
||||||
s.save( you );
|
|
||||||
s.save( yourClock );
|
|
||||||
s.save( task );
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
StatelessSession ss = sessionFactory().openStatelessSession();
|
|
||||||
ss.beginTransaction();
|
|
||||||
Task taskRef = (Task) ss.createQuery( "from Task t join fetch t.resource join fetch t.user" ).uniqueResult();
|
|
||||||
assertNotNull( taskRef );
|
|
||||||
assertTrue( Hibernate.isInitialized( taskRef ) );
|
|
||||||
assertTrue( Hibernate.isInitialized( taskRef.getUser() ) );
|
|
||||||
assertTrue( Hibernate.isInitialized( taskRef.getResource() ) );
|
|
||||||
assertFalse( Hibernate.isInitialized( taskRef.getResource().getOwner() ) );
|
|
||||||
ss.getTransaction().commit();
|
|
||||||
ss.close();
|
|
||||||
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDynamicFetchScroll() {
|
|
||||||
Session s = openSession();
|
|
||||||
s.beginTransaction();
|
|
||||||
Date now = new Date();
|
|
||||||
|
|
||||||
User me = new User( "me" );
|
|
||||||
User you = new User( "you" );
|
|
||||||
Resource yourClock = new Resource( "clock", you );
|
|
||||||
Task task = new Task( me, "clean", yourClock, now ); // :)
|
|
||||||
|
|
||||||
s.save( me );
|
|
||||||
s.save( you );
|
|
||||||
s.save( yourClock );
|
|
||||||
s.save( task );
|
|
||||||
|
|
||||||
User u3 = new User( "U3" );
|
|
||||||
User u4 = new User( "U4" );
|
|
||||||
Resource it = new Resource( "it", u4 );
|
|
||||||
Task task2 = new Task( u3, "beat", it, now ); // :))
|
|
||||||
|
|
||||||
s.save( u3 );
|
|
||||||
s.save( u4 );
|
|
||||||
s.save( it );
|
|
||||||
s.save( task2 );
|
|
||||||
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
StatelessSession ss = sessionFactory().openStatelessSession();
|
|
||||||
ss.beginTransaction();
|
|
||||||
|
|
||||||
final Query query = ss.createQuery( "from Task t join fetch t.resource join fetch t.user" );
|
|
||||||
final ScrollableResults scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
|
|
||||||
while ( scrollableResults.next() ) {
|
|
||||||
Task taskRef = (Task) scrollableResults.get();
|
|
||||||
assertTrue( Hibernate.isInitialized( taskRef ) );
|
|
||||||
assertTrue( Hibernate.isInitialized( taskRef.getUser() ) );
|
|
||||||
assertTrue( Hibernate.isInitialized( taskRef.getResource() ) );
|
|
||||||
assertFalse( Hibernate.isInitialized( taskRef.getResource().getOwner() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
ss.getTransaction().commit();
|
|
||||||
ss.close();
|
|
||||||
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDynamicFetchScrollSession() {
|
|
||||||
Session s = openSession();
|
|
||||||
s.beginTransaction();
|
|
||||||
Date now = new Date();
|
|
||||||
|
|
||||||
User me = new User( "me" );
|
|
||||||
User you = new User( "you" );
|
|
||||||
Resource yourClock = new Resource( "clock", you );
|
|
||||||
Task task = new Task( me, "clean", yourClock, now ); // :)
|
|
||||||
|
|
||||||
s.save( me );
|
|
||||||
s.save( you );
|
|
||||||
s.save( yourClock );
|
|
||||||
s.save( task );
|
|
||||||
|
|
||||||
User u3 = new User( "U3" );
|
|
||||||
User u4 = new User( "U4" );
|
|
||||||
Resource it = new Resource( "it", u4 );
|
|
||||||
Task task2 = new Task( u3, "beat", it, now ); // :))
|
|
||||||
|
|
||||||
s.save( u3 );
|
|
||||||
s.save( u4 );
|
|
||||||
s.save( it );
|
|
||||||
s.save( task2 );
|
|
||||||
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
inTransaction(
|
|
||||||
session -> {
|
|
||||||
final Query query = session.createQuery( "from Task t join fetch t.resource join fetch t.user" );
|
|
||||||
final ScrollableResults scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY );
|
|
||||||
while ( scrollableResults.next() ) {
|
|
||||||
Task taskRef = (Task) scrollableResults.get();
|
|
||||||
assertTrue( Hibernate.isInitialized( taskRef ) );
|
|
||||||
assertTrue( Hibernate.isInitialized( taskRef.getUser() ) );
|
|
||||||
assertTrue( Hibernate.isInitialized( taskRef.getResource() ) );
|
|
||||||
assertFalse( Hibernate.isInitialized( taskRef.getResource().getOwner() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDynamicFetchCollectionScroll() {
|
|
||||||
Session s = openSession();
|
|
||||||
s.beginTransaction();
|
|
||||||
|
|
||||||
Producer p1 = new Producer( 1, "Acme" );
|
|
||||||
Producer p2 = new Producer( 2, "ABC" );
|
|
||||||
|
|
||||||
session.save( p1 );
|
|
||||||
session.save( p2 );
|
|
||||||
|
|
||||||
Vendor v1 = new Vendor( 1, "v1" );
|
|
||||||
Vendor v2 = new Vendor( 2, "v2" );
|
|
||||||
|
|
||||||
session.save( v1 );
|
|
||||||
session.save( v2 );
|
|
||||||
|
|
||||||
final Product product1 = new Product( 1, "123", v1, p1 );
|
|
||||||
final Product product2 = new Product( 2, "456", v1, p1 );
|
|
||||||
final Product product3 = new Product( 3, "789", v1, p2 );
|
|
||||||
|
|
||||||
session.save( product1 );
|
|
||||||
session.save( product2 );
|
|
||||||
session.save( product3 );
|
|
||||||
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
StatelessSession ss = sessionFactory().openStatelessSession();
|
|
||||||
ss.beginTransaction();
|
|
||||||
|
|
||||||
final Query query = ss.createQuery( "select p from Producer p join fetch p.products" );
|
|
||||||
final ScrollableResults scrollableResults = getScrollableResults( query );
|
|
||||||
|
|
||||||
while ( scrollableResults.next() ) {
|
|
||||||
Producer producer = (Producer) scrollableResults.get();
|
|
||||||
assertTrue( Hibernate.isInitialized( producer ) );
|
|
||||||
assertTrue( Hibernate.isInitialized( producer.getProducts() ) );
|
|
||||||
|
|
||||||
for ( Product product : producer.getProducts() ) {
|
|
||||||
assertTrue( Hibernate.isInitialized( product ) );
|
|
||||||
assertFalse( Hibernate.isInitialized( product.getVendor() ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ss.getTransaction().commit();
|
|
||||||
ss.close();
|
|
||||||
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScrollableResults getScrollableResults(Query query) {
|
|
||||||
ScrollableResults scrollableResults;
|
|
||||||
if ( getDialect() instanceof DB2Dialect ) {
|
|
||||||
/*
|
|
||||||
FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst()
|
|
||||||
but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result
|
|
||||||
set type of TYPE_FORWARD_ONLY and db2 does not support it.
|
|
||||||
*/
|
|
||||||
return query.scroll( ScrollMode.SCROLL_INSENSITIVE );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return query.scroll( ScrollMode.FORWARD_ONLY );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cleanup() {
|
|
||||||
Session s = openSession();
|
|
||||||
s.beginTransaction();
|
|
||||||
s.createQuery( "delete Task" ).executeUpdate();
|
|
||||||
s.createQuery( "delete Resource" ).executeUpdate();
|
|
||||||
s.createQuery( "delete User" ).executeUpdate();
|
|
||||||
|
|
||||||
s.createQuery( "delete Product" ).executeUpdate();
|
|
||||||
s.createQuery( "delete Producer" ).executeUpdate();
|
|
||||||
s.createQuery( "delete Vendor" ).executeUpdate();
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.test.stateless.insert;
|
|
||||||
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.StatelessSession;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author mukhanov@gmail.com
|
|
||||||
*/
|
|
||||||
public class StatelessSessionInsertTest extends BaseCoreFunctionalTestCase {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getMappings() {
|
|
||||||
return new String[]{"stateless/insert/Mappings.hbm.xml"};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInsertWithForeignKey() {
|
|
||||||
Session session = sessionFactory().openSession();
|
|
||||||
Transaction tx = session.beginTransaction();
|
|
||||||
|
|
||||||
Message msg = new Message();
|
|
||||||
final String messageId = "message_id";
|
|
||||||
msg.setId(messageId);
|
|
||||||
msg.setContent("message_content");
|
|
||||||
msg.setSubject("message_subject");
|
|
||||||
session.save(msg);
|
|
||||||
|
|
||||||
tx.commit();
|
|
||||||
session.close();
|
|
||||||
|
|
||||||
StatelessSession statelessSession = sessionFactory().openStatelessSession();
|
|
||||||
tx = statelessSession.beginTransaction();
|
|
||||||
|
|
||||||
MessageRecipient signature = new MessageRecipient();
|
|
||||||
signature.setId("recipient");
|
|
||||||
signature.setEmail("recipient@hibernate.org");
|
|
||||||
signature.setMessage(msg);
|
|
||||||
statelessSession.insert(signature);
|
|
||||||
|
|
||||||
tx.commit();
|
|
||||||
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cleanup() {
|
|
||||||
Session s = openSession();
|
|
||||||
s.beginTransaction();
|
|
||||||
s.createQuery("delete MessageRecipient").executeUpdate();
|
|
||||||
s.createQuery("delete Message").executeUpdate();
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.testing.orm.logger;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.hibernate.testing.logger.LogInspectionHelper;
|
|
||||||
import org.hibernate.testing.logger.LogListener;
|
|
||||||
import org.hibernate.testing.logger.TriggerOnPrefixLogListener;
|
|
||||||
import org.hibernate.testing.logger.Triggerable;
|
|
||||||
|
|
||||||
import org.jboss.logging.BasicLogger;
|
|
||||||
|
|
||||||
public class Inspector {
|
|
||||||
private BasicLogger log;
|
|
||||||
|
|
||||||
public void init(BasicLogger logger){
|
|
||||||
log = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicLogger getLog(){
|
|
||||||
return log;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Triggerable watchForLogMessages(String prefix) {
|
|
||||||
TriggerOnPrefixLogListener listener = new TriggerOnPrefixLogListener( prefix );
|
|
||||||
registerListener( listener );
|
|
||||||
return listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Triggerable watchForLogMessages(Set<String> prefixes) {
|
|
||||||
TriggerOnPrefixLogListener listener = new TriggerOnPrefixLogListener( prefixes );
|
|
||||||
registerListener( listener );
|
|
||||||
return listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerListener(LogListener listener) {
|
|
||||||
LogInspectionHelper.registerListener( listener, log );
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.testing.orm.logger;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target(ElementType.PARAMETER)
|
|
||||||
public @interface LogInspector {
|
|
||||||
}
|
|
|
@ -1,46 +1,65 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
*/
|
*/
|
||||||
package org.hibernate.testing.orm.logger;
|
package org.hibernate.testing.orm.logger;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.testing.logger.LogInspectionHelper;
|
import org.hibernate.testing.logger.LogInspectionHelper;
|
||||||
|
import org.hibernate.testing.logger.LogListener;
|
||||||
|
import org.hibernate.testing.logger.TriggerOnPrefixLogListener;
|
||||||
|
import org.hibernate.testing.logger.Triggerable;
|
||||||
import org.junit.jupiter.api.extension.AfterEachCallback;
|
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
|
||||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||||
import org.junit.jupiter.api.extension.ParameterContext;
|
|
||||||
import org.junit.jupiter.api.extension.ParameterResolutionException;
|
|
||||||
import org.junit.jupiter.api.extension.ParameterResolver;
|
|
||||||
|
|
||||||
public final class LoggerInspectionExtension implements AfterEachCallback, BeforeEachCallback, ParameterResolver {
|
import org.jboss.logging.BasicLogger;
|
||||||
|
|
||||||
private Inspector inspector;
|
public class LoggerInspectionExtension implements AfterEachCallback {
|
||||||
|
|
||||||
public LoggerInspectionExtension() {
|
public static LoggerInspectionExtension.LoggerInspectionRuleBuilder builder() {
|
||||||
inspector = new Inspector();
|
return new LoggerInspectionExtension.LoggerInspectionRuleBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class LoggerInspectionRuleBuilder {
|
||||||
public void beforeEach(ExtensionContext context) throws Exception {
|
BasicLogger log;
|
||||||
// do nothing
|
|
||||||
|
public LoggerInspectionExtension.LoggerInspectionRuleBuilder setLogger(BasicLogger log) {
|
||||||
|
this.log = log;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoggerInspectionExtension build() {
|
||||||
|
return new LoggerInspectionExtension( log );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final BasicLogger log;
|
||||||
|
|
||||||
|
public LoggerInspectionExtension(BasicLogger log) {
|
||||||
|
this.log = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerListener(LogListener listener) {
|
||||||
|
LogInspectionHelper.registerListener( listener, log );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Triggerable watchForLogMessages(String prefix) {
|
||||||
|
TriggerOnPrefixLogListener listener = new TriggerOnPrefixLogListener( prefix );
|
||||||
|
registerListener( listener );
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Triggerable watchForLogMessages(Set<String> prefixes) {
|
||||||
|
TriggerOnPrefixLogListener listener = new TriggerOnPrefixLogListener( prefixes );
|
||||||
|
registerListener( listener );
|
||||||
|
return listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterEach(ExtensionContext context) throws Exception {
|
public void afterEach(ExtensionContext context) throws Exception {
|
||||||
LogInspectionHelper.clearAllListeners( inspector.getLog() );
|
LogInspectionHelper.clearAllListeners( log );
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsParameter(
|
|
||||||
ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
|
|
||||||
return parameterContext.isAnnotated( LogInspector.class );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object resolveParameter(
|
|
||||||
ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
|
|
||||||
return inspector;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue