mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-17 00:24:57 +00:00
Move more tests to o.h.orm.test
This commit is contained in:
parent
28f4d62f6a
commit
a96096bc28
@ -0,0 +1,697 @@
|
||||
/*
|
||||
* 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.cascade.circle;
|
||||
|
||||
import java.util.Iterator;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.PropertyValueException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.TransientPropertyValueException;
|
||||
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public abstract class AbstractMultiPathCircleCascadeTest {
|
||||
private interface EntityOperation {
|
||||
boolean isLegacy();
|
||||
|
||||
Object doEntityOperation(Object entity, Session s);
|
||||
}
|
||||
|
||||
private static EntityOperation MERGE_OPERATION =
|
||||
new EntityOperation() {
|
||||
@Override
|
||||
public boolean isLegacy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object doEntityOperation(Object entity, Session s) {
|
||||
return s.merge( entity );
|
||||
}
|
||||
};
|
||||
private static EntityOperation SAVE_OPERATION =
|
||||
new EntityOperation() {
|
||||
@Override
|
||||
public boolean isLegacy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object doEntityOperation(Object entity, Session s) {
|
||||
s.save( entity );
|
||||
return entity;
|
||||
}
|
||||
};
|
||||
private static EntityOperation SAVE_UPDATE_OPERATION =
|
||||
new EntityOperation() {
|
||||
@Override
|
||||
public boolean isLegacy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object doEntityOperation(Object entity, Session s) {
|
||||
s.saveOrUpdate( entity );
|
||||
return entity;
|
||||
}
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testMergeEntityWithNonNullableTransientEntity(SessionFactoryScope scope) {
|
||||
testEntityWithNonNullableTransientEntity( scope, MERGE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveEntityWithNonNullableTransientEntity(SessionFactoryScope scope) {
|
||||
testEntityWithNonNullableTransientEntity( scope, SAVE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveUpdateEntityWithNonNullableTransientEntity(SessionFactoryScope scope) {
|
||||
testEntityWithNonNullableTransientEntity( scope, SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
|
||||
private void testEntityWithNonNullableTransientEntity(SessionFactoryScope scope, EntityOperation operation) {
|
||||
|
||||
Route route = getUpdatedDetachedEntity( scope );
|
||||
|
||||
Node node = (Node) route.getNodes().iterator().next();
|
||||
route.getNodes().remove( node );
|
||||
|
||||
Route routeNew = new Route();
|
||||
routeNew.setName( "new route" );
|
||||
routeNew.getNodes().add( node );
|
||||
node.setRoute( routeNew );
|
||||
|
||||
scope.inSession(
|
||||
session -> {
|
||||
session.beginTransaction();
|
||||
try {
|
||||
operation.doEntityOperation( node, session );
|
||||
session.getTransaction().commit();
|
||||
fail( "should have thrown an exception" );
|
||||
}
|
||||
catch (Exception ex) {
|
||||
checkExceptionFromNullValueForNonNullable(
|
||||
ex,
|
||||
session.getFactory().getSessionFactoryOptions().isCheckNullability(),
|
||||
false,
|
||||
operation.isLegacy()
|
||||
);
|
||||
}
|
||||
finally {
|
||||
session.getTransaction().rollback();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeEntityWithNonNullableEntityNull(SessionFactoryScope scope) {
|
||||
testEntityWithNonNullableEntityNull( scope, MERGE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveEntityWithNonNullableEntityNull(SessionFactoryScope scope) {
|
||||
testEntityWithNonNullableEntityNull( scope, SAVE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveUpdateEntityWithNonNullableEntityNull(SessionFactoryScope scope) {
|
||||
testEntityWithNonNullableEntityNull( scope, SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
|
||||
private void testEntityWithNonNullableEntityNull(SessionFactoryScope scope, EntityOperation operation) {
|
||||
Route route = getUpdatedDetachedEntity( scope );
|
||||
|
||||
Node node = (Node) route.getNodes().iterator().next();
|
||||
route.getNodes().remove( node );
|
||||
node.setRoute( null );
|
||||
|
||||
scope.inSession(
|
||||
session -> {
|
||||
session.beginTransaction();
|
||||
try {
|
||||
operation.doEntityOperation( node, session );
|
||||
session.getTransaction().commit();
|
||||
fail( "should have thrown an exception" );
|
||||
}
|
||||
catch (Exception ex) {
|
||||
checkExceptionFromNullValueForNonNullable(
|
||||
ex,
|
||||
session.getFactory().getSessionFactoryOptions().isCheckNullability(),
|
||||
true,
|
||||
operation.isLegacy()
|
||||
);
|
||||
}
|
||||
finally {
|
||||
session.getTransaction().rollback();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeEntityWithNonNullablePropSetToNull(SessionFactoryScope scope) {
|
||||
testEntityWithNonNullablePropSetToNull( scope, MERGE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveEntityWithNonNullablePropSetToNull(SessionFactoryScope scope) {
|
||||
testEntityWithNonNullablePropSetToNull( scope, SAVE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveUpdateEntityWithNonNullablePropSetToNull(SessionFactoryScope scope) {
|
||||
testEntityWithNonNullablePropSetToNull( scope, SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
|
||||
private void testEntityWithNonNullablePropSetToNull(SessionFactoryScope scope, EntityOperation operation) {
|
||||
Route route = getUpdatedDetachedEntity( scope );
|
||||
Node node = (Node) route.getNodes().iterator().next();
|
||||
node.setName( null );
|
||||
|
||||
scope.inSession(
|
||||
session -> {
|
||||
session.beginTransaction();
|
||||
|
||||
try {
|
||||
operation.doEntityOperation( route, session );
|
||||
session.getTransaction().commit();
|
||||
fail( "should have thrown an exception" );
|
||||
}
|
||||
catch (Exception ex) {
|
||||
checkExceptionFromNullValueForNonNullable(
|
||||
ex,
|
||||
session.getFactory().getSessionFactoryOptions().isCheckNullability(),
|
||||
true,
|
||||
operation.isLegacy()
|
||||
);
|
||||
}
|
||||
finally {
|
||||
session.getTransaction().rollback();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeRoute(SessionFactoryScope scope) {
|
||||
testRoute( scope, MERGE_OPERATION );
|
||||
}
|
||||
|
||||
// skip SAVE_OPERATION since Route is not transient
|
||||
@Test
|
||||
public void testSaveUpdateRoute(SessionFactoryScope scope) {
|
||||
testRoute( scope, SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
|
||||
private void testRoute(SessionFactoryScope scope, EntityOperation operation) {
|
||||
|
||||
Route r = getUpdatedDetachedEntity( scope );
|
||||
|
||||
clearCounts( scope );
|
||||
|
||||
scope.inTransaction(
|
||||
session ->
|
||||
operation.doEntityOperation( r, session )
|
||||
);
|
||||
|
||||
assertInsertCount( scope, 4 );
|
||||
assertUpdateCount( scope, 1 );
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Route route = session.get( Route.class, r.getRouteID() );
|
||||
checkResults( route, true );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergePickupNode(SessionFactoryScope scope) {
|
||||
testPickupNode( scope, MERGE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavePickupNode(SessionFactoryScope scope) {
|
||||
testPickupNode( scope, SAVE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveUpdatePickupNode(SessionFactoryScope scope) {
|
||||
testPickupNode( scope, SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
|
||||
private void testPickupNode(SessionFactoryScope scope, EntityOperation operation) {
|
||||
|
||||
Route r = getUpdatedDetachedEntity( scope );
|
||||
|
||||
clearCounts( scope );
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Iterator it = r.getNodes().iterator();
|
||||
Node node = (Node) it.next();
|
||||
Node pickupNode;
|
||||
if ( node.getName().equals( "pickupNodeB" ) ) {
|
||||
pickupNode = node;
|
||||
}
|
||||
else {
|
||||
node = (Node) it.next();
|
||||
assertEquals( "pickupNodeB", node.getName() );
|
||||
pickupNode = node;
|
||||
}
|
||||
|
||||
operation.doEntityOperation( pickupNode, session );
|
||||
}
|
||||
);
|
||||
|
||||
assertInsertCount( scope, 4 );
|
||||
assertUpdateCount( scope, 0 );
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Route route = session.get( Route.class, r.getRouteID() );
|
||||
checkResults( route, false );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeDeliveryNode(SessionFactoryScope scope) {
|
||||
testDeliveryNode( scope, MERGE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveDeliveryNode(SessionFactoryScope scope) {
|
||||
testDeliveryNode( scope, SAVE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveUpdateDeliveryNode(SessionFactoryScope scope) {
|
||||
testDeliveryNode( scope, SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
|
||||
private void testDeliveryNode(SessionFactoryScope scope, EntityOperation operation) {
|
||||
|
||||
Route r = getUpdatedDetachedEntity( scope );
|
||||
|
||||
clearCounts( scope );
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Iterator it = r.getNodes().iterator();
|
||||
Node node = (Node) it.next();
|
||||
Node deliveryNode;
|
||||
if ( node.getName().equals( "deliveryNodeB" ) ) {
|
||||
deliveryNode = node;
|
||||
}
|
||||
else {
|
||||
node = (Node) it.next();
|
||||
assertEquals( "deliveryNodeB", node.getName() );
|
||||
deliveryNode = node;
|
||||
}
|
||||
|
||||
operation.doEntityOperation( deliveryNode, session );
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
assertInsertCount( scope, 4 );
|
||||
assertUpdateCount( scope, 0 );
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Route route = session.get( Route.class, r.getRouteID() );
|
||||
checkResults( route, false );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeTour(SessionFactoryScope scope) {
|
||||
testTour( scope, MERGE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveTour(SessionFactoryScope scope) {
|
||||
testTour( scope, SAVE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveUpdateTour(SessionFactoryScope scope) {
|
||||
testTour( scope, SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
|
||||
private void testTour(SessionFactoryScope scope, EntityOperation operation) {
|
||||
|
||||
Route r = getUpdatedDetachedEntity( scope );
|
||||
|
||||
clearCounts( scope );
|
||||
|
||||
scope.inTransaction(
|
||||
session ->
|
||||
operation.doEntityOperation( ( (Node) r.getNodes().toArray()[0] ).getTour(), session )
|
||||
);
|
||||
|
||||
assertInsertCount( scope, 4 );
|
||||
assertUpdateCount( scope, 0 );
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Route route = session.get( Route.class, r.getRouteID() );
|
||||
checkResults( route, false );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeTransport(SessionFactoryScope scope) {
|
||||
testTransport( scope, MERGE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveTransport(SessionFactoryScope scope) {
|
||||
testTransport( scope, SAVE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveUpdateTransport(SessionFactoryScope scope) {
|
||||
testTransport( scope, SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
|
||||
private void testTransport(SessionFactoryScope scope, EntityOperation operation) {
|
||||
|
||||
Route r = getUpdatedDetachedEntity( scope );
|
||||
|
||||
clearCounts( scope );
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Transport transport;
|
||||
Node node = ( (Node) r.getNodes().toArray()[0] );
|
||||
if ( node.getPickupTransports().size() == 1 ) {
|
||||
transport = (Transport) node.getPickupTransports().toArray()[0];
|
||||
}
|
||||
else {
|
||||
transport = (Transport) node.getDeliveryTransports().toArray()[0];
|
||||
}
|
||||
|
||||
operation.doEntityOperation( transport, session );
|
||||
}
|
||||
);
|
||||
|
||||
assertInsertCount( scope, 4 );
|
||||
assertUpdateCount( scope, 0 );
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Route route = session.get( Route.class, r.getRouteID() );
|
||||
checkResults( route, false );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private Node getSimpleUpdatedDetachedEntity() {
|
||||
|
||||
Node deliveryNode = new Node();
|
||||
deliveryNode.setName( "deliveryNodeB" );
|
||||
return deliveryNode;
|
||||
}
|
||||
|
||||
private Route getUpdatedDetachedEntity(SessionFactoryScope scope) {
|
||||
|
||||
Route route = new Route();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
route.setName( "routeA" );
|
||||
|
||||
session.save( route );
|
||||
}
|
||||
);
|
||||
|
||||
route.setName( "new routeA" );
|
||||
route.setTransientField( "sfnaouisrbn" );
|
||||
|
||||
Tour tour = new Tour();
|
||||
tour.setName( "tourB" );
|
||||
|
||||
Transport transport = new Transport();
|
||||
transport.setName( "transportB" );
|
||||
|
||||
Node pickupNode = new Node();
|
||||
pickupNode.setName( "pickupNodeB" );
|
||||
|
||||
Node deliveryNode = new Node();
|
||||
deliveryNode.setName( "deliveryNodeB" );
|
||||
|
||||
pickupNode.setRoute( route );
|
||||
pickupNode.setTour( tour );
|
||||
pickupNode.getPickupTransports().add( transport );
|
||||
pickupNode.setTransientField( "pickup node aaaaaaaaaaa" );
|
||||
|
||||
deliveryNode.setRoute( route );
|
||||
deliveryNode.setTour( tour );
|
||||
deliveryNode.getDeliveryTransports().add( transport );
|
||||
deliveryNode.setTransientField( "delivery node aaaaaaaaa" );
|
||||
|
||||
tour.getNodes().add( pickupNode );
|
||||
tour.getNodes().add( deliveryNode );
|
||||
|
||||
route.getNodes().add( pickupNode );
|
||||
route.getNodes().add( deliveryNode );
|
||||
|
||||
transport.setPickupNode( pickupNode );
|
||||
transport.setDeliveryNode( deliveryNode );
|
||||
transport.setTransientField( "aaaaaaaaaaaaaa" );
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanup(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete from Transport" );
|
||||
session.createQuery( "delete from Tour" );
|
||||
session.createQuery( "delete from Node" );
|
||||
session.createQuery( "delete from Route" );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void checkResults(Route route, boolean isRouteUpdated) {
|
||||
// since no cascaded to route, this method needs to
|
||||
// know whether route is expected to be updated
|
||||
if ( isRouteUpdated ) {
|
||||
assertEquals( "new routeA", route.getName() );
|
||||
}
|
||||
assertEquals( 2, route.getNodes().size() );
|
||||
Node deliveryNode = null;
|
||||
Node pickupNode = null;
|
||||
for ( Iterator it = route.getNodes().iterator(); it.hasNext(); ) {
|
||||
Node node = (Node) it.next();
|
||||
if ( "deliveryNodeB".equals( node.getName() ) ) {
|
||||
deliveryNode = node;
|
||||
}
|
||||
else if ( "pickupNodeB".equals( node.getName() ) ) {
|
||||
pickupNode = node;
|
||||
}
|
||||
else {
|
||||
fail( "unknown node" );
|
||||
}
|
||||
}
|
||||
assertNotNull( deliveryNode );
|
||||
assertSame( route, deliveryNode.getRoute() );
|
||||
assertEquals( 1, deliveryNode.getDeliveryTransports().size() );
|
||||
assertEquals( 0, deliveryNode.getPickupTransports().size() );
|
||||
assertNotNull( deliveryNode.getTour() );
|
||||
assertEquals( "node original value", deliveryNode.getTransientField() );
|
||||
|
||||
assertNotNull( pickupNode );
|
||||
assertSame( route, pickupNode.getRoute() );
|
||||
assertEquals( 0, pickupNode.getDeliveryTransports().size() );
|
||||
assertEquals( 1, pickupNode.getPickupTransports().size() );
|
||||
assertNotNull( pickupNode.getTour() );
|
||||
assertEquals( "node original value", pickupNode.getTransientField() );
|
||||
|
||||
assertTrue( !deliveryNode.getNodeID().equals( pickupNode.getNodeID() ) );
|
||||
assertSame( deliveryNode.getTour(), pickupNode.getTour() );
|
||||
assertSame(
|
||||
deliveryNode.getDeliveryTransports().iterator().next(),
|
||||
pickupNode.getPickupTransports().iterator().next()
|
||||
);
|
||||
|
||||
Tour tour = deliveryNode.getTour();
|
||||
Transport transport = (Transport) deliveryNode.getDeliveryTransports().iterator().next();
|
||||
|
||||
assertEquals( "tourB", tour.getName() );
|
||||
assertEquals( 2, tour.getNodes().size() );
|
||||
assertTrue( tour.getNodes().contains( deliveryNode ) );
|
||||
assertTrue( tour.getNodes().contains( pickupNode ) );
|
||||
|
||||
assertEquals( "transportB", transport.getName() );
|
||||
assertSame( deliveryNode, transport.getDeliveryNode() );
|
||||
assertSame( pickupNode, transport.getPickupNode() );
|
||||
assertEquals( "transport original value", transport.getTransientField() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeData3Nodes(SessionFactoryScope scope) {
|
||||
testData3Nodes( scope, MERGE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveData3Nodes(SessionFactoryScope scope) {
|
||||
testData3Nodes( scope, SAVE_OPERATION );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveUpdateData3Nodes(SessionFactoryScope scope) {
|
||||
testData3Nodes( scope, SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
|
||||
private void testData3Nodes(SessionFactoryScope scope, EntityOperation operation) {
|
||||
|
||||
Route r = new Route();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
r.setName( "routeA" );
|
||||
|
||||
session.save( r );
|
||||
}
|
||||
);
|
||||
|
||||
clearCounts( scope );
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Route route = session.get( Route.class, r.getRouteID() );
|
||||
route.setName( "new routA" );
|
||||
|
||||
route.setTransientField( "sfnaouisrbn" );
|
||||
|
||||
Tour tour = new Tour();
|
||||
tour.setName( "tourB" );
|
||||
|
||||
Transport transport1 = new Transport();
|
||||
transport1.setName( "TRANSPORT1" );
|
||||
|
||||
Transport transport2 = new Transport();
|
||||
transport2.setName( "TRANSPORT2" );
|
||||
|
||||
Node node1 = new Node();
|
||||
node1.setName( "NODE1" );
|
||||
|
||||
Node node2 = new Node();
|
||||
node2.setName( "NODE2" );
|
||||
|
||||
Node node3 = new Node();
|
||||
node3.setName( "NODE3" );
|
||||
|
||||
node1.setRoute( route );
|
||||
node1.setTour( tour );
|
||||
node1.getPickupTransports().add( transport1 );
|
||||
node1.setTransientField( "node 1" );
|
||||
|
||||
node2.setRoute( route );
|
||||
node2.setTour( tour );
|
||||
node2.getDeliveryTransports().add( transport1 );
|
||||
node2.getPickupTransports().add( transport2 );
|
||||
node2.setTransientField( "node 2" );
|
||||
|
||||
node3.setRoute( route );
|
||||
node3.setTour( tour );
|
||||
node3.getDeliveryTransports().add( transport2 );
|
||||
node3.setTransientField( "node 3" );
|
||||
|
||||
tour.getNodes().add( node1 );
|
||||
tour.getNodes().add( node2 );
|
||||
tour.getNodes().add( node3 );
|
||||
|
||||
route.getNodes().add( node1 );
|
||||
route.getNodes().add( node2 );
|
||||
route.getNodes().add( node3 );
|
||||
|
||||
transport1.setPickupNode( node1 );
|
||||
transport1.setDeliveryNode( node2 );
|
||||
transport1.setTransientField( "aaaaaaaaaaaaaa" );
|
||||
|
||||
transport2.setPickupNode( node2 );
|
||||
transport2.setDeliveryNode( node3 );
|
||||
transport2.setTransientField( "bbbbbbbbbbbbb" );
|
||||
|
||||
operation.doEntityOperation( route, session );
|
||||
}
|
||||
);
|
||||
|
||||
assertInsertCount( scope, 6 );
|
||||
assertUpdateCount( scope, 1 );
|
||||
}
|
||||
|
||||
protected void checkExceptionFromNullValueForNonNullable(
|
||||
Exception ex, boolean checkNullability, boolean isNullValue, boolean isLegacy
|
||||
) {
|
||||
if ( isNullValue ) {
|
||||
if ( checkNullability ) {
|
||||
if ( isLegacy ) {
|
||||
assertTyping( PropertyValueException.class, ex );
|
||||
}
|
||||
else {
|
||||
assertTyping( PersistenceException.class, ex );
|
||||
}
|
||||
}
|
||||
else {
|
||||
assertTrue( ( ex instanceof JDBCException ) || ( ex.getCause() instanceof JDBCException ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( isLegacy ) {
|
||||
assertTyping( TransientPropertyValueException.class, ex );
|
||||
}
|
||||
else {
|
||||
assertTyping( IllegalStateException.class, ex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void clearCounts(SessionFactoryScope scope) {
|
||||
scope.getSessionFactory().getStatistics().clear();
|
||||
}
|
||||
|
||||
protected void assertInsertCount(SessionFactoryScope scope, int expected) {
|
||||
int inserts = (int) scope.getSessionFactory().getStatistics().getEntityInsertCount();
|
||||
assertEquals( expected, inserts, "unexpected insert count" );
|
||||
}
|
||||
|
||||
protected void assertUpdateCount(SessionFactoryScope scope, int expected) {
|
||||
int updates = (int) scope.getSessionFactory().getStatistics().getEntityUpdateCount();
|
||||
assertEquals( expected, updates, "unexpected update counts" );
|
||||
}
|
||||
|
||||
protected void assertDeleteCount(SessionFactoryScope scope, int expected) {
|
||||
int deletes = (int) scope.getSessionFactory().getStatistics().getEntityDeleteCount();
|
||||
assertEquals( expected, deletes, "unexpected delete counts" );
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.cascade.circle">
|
||||
<hibernate-mapping package="org.hibernate.orm.test.cascade.circle">
|
||||
|
||||
<class name="Route" table="HB_Route">
|
||||
|
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* 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.cascade.circle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
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.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* The test case uses the following model:
|
||||
* <p>
|
||||
* <- ->
|
||||
* -- (N : 0,1) -- Tour
|
||||
* | <- ->
|
||||
* | -- (1 : N) -- (pickup) ----
|
||||
* <- -> | | |
|
||||
* Route -- (1 : N) -- Node Transport
|
||||
* | <- -> |
|
||||
* -- (1 : N) -- (delivery) --
|
||||
* <p>
|
||||
* Arrows indicate the direction of cascade-merge, cascade-save, cascade-refresh and cascade-save-or-update
|
||||
* <p>
|
||||
* It reproduces the following issues:
|
||||
* https://hibernate.atlassian.net/browse/HHH-9512
|
||||
* <p/>
|
||||
* This tests that cascades are done properly from each entity.
|
||||
*
|
||||
* @author Alex Belyaev (based on code by Pavol Zibrita and Gail Badner)
|
||||
*/
|
||||
@DomainModel(
|
||||
xmlMappings = {
|
||||
"org/hibernate/orm/test/cascade/circle/CascadeManagedAndTransient.hbm.xml"
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@ServiceRegistry(
|
||||
settings = @ServiceRegistry.Setting(name = Environment.CHECK_NULLABILITY, value = "true")
|
||||
)
|
||||
public class CascadeManagedAndTransientTest {
|
||||
|
||||
@AfterEach
|
||||
public void cleanupTest(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete from Transport" );
|
||||
session.createQuery( "delete from Tour" );
|
||||
session.createQuery( "delete from Node" );
|
||||
session.createQuery( "delete from Route" );
|
||||
session.createQuery( "delete from Vehicle" );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttachedChildInMerge(SessionFactoryScope scope) {
|
||||
fillInitialData( scope );
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Route route = (Route) session.createQuery( "FROM Route WHERE name = :name" )
|
||||
.setParameter( "name", "Route 1" )
|
||||
.uniqueResult();
|
||||
Node n2 = (Node) session.createQuery( "FROM Node WHERE name = :name" )
|
||||
.setParameter( "name", "Node 2" )
|
||||
.uniqueResult();
|
||||
Node n3 = (Node) session.createQuery( "FROM Node WHERE name = :name" )
|
||||
.setParameter( "name", "Node 3" )
|
||||
.uniqueResult();
|
||||
|
||||
Vehicle vehicle = new Vehicle();
|
||||
vehicle.setName( "Bus" );
|
||||
vehicle.setRoute( route );
|
||||
|
||||
Transport $2to3 = new Transport();
|
||||
$2to3.setName( "Transport 2 -> 3" );
|
||||
$2to3.setPickupNode( n2 );
|
||||
n2.getPickupTransports().add( $2to3 );
|
||||
$2to3.setDeliveryNode( n3 );
|
||||
n3.getDeliveryTransports().add( $2to3 );
|
||||
$2to3.setVehicle( vehicle );
|
||||
|
||||
vehicle.setTransports( new HashSet<Transport>( Arrays.asList( $2to3 ) ) );
|
||||
|
||||
// Try to save graph of transient entities (vehicle, transport) which contains attached entities (node2, node3)
|
||||
Vehicle managedVehicle = (Vehicle) session.merge( vehicle );
|
||||
checkNewVehicle( managedVehicle );
|
||||
|
||||
session.flush();
|
||||
session.clear();
|
||||
|
||||
assertEquals( 3, session.createQuery( "FROM Transport" ).list().size() );
|
||||
assertEquals( 2, session.createQuery( "FROM Vehicle" ).list().size() );
|
||||
assertEquals( 4, session.createQuery( "FROM Node" ).list().size() );
|
||||
|
||||
Vehicle newVehicle = (Vehicle) session.createQuery( "FROM Vehicle WHERE name = :name" )
|
||||
.setParameter( "name", "Bus" )
|
||||
.uniqueResult();
|
||||
checkNewVehicle( newVehicle );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void checkNewVehicle(Vehicle newVehicle) {
|
||||
assertEquals( "Bus", newVehicle.getName() );
|
||||
assertEquals( 1, newVehicle.getTransports().size() );
|
||||
Transport t = (Transport) newVehicle.getTransports().iterator().next();
|
||||
assertEquals( "Transport 2 -> 3", t.getName() );
|
||||
assertEquals( "Node 2", t.getPickupNode().getName() );
|
||||
assertEquals( "Node 3", t.getDeliveryNode().getName() );
|
||||
}
|
||||
|
||||
private void fillInitialData(SessionFactoryScope scope) {
|
||||
Tour tour = new Tour();
|
||||
tour.setName( "Tour 1" );
|
||||
|
||||
Route route = new Route();
|
||||
route.setName( "Route 1" );
|
||||
|
||||
ArrayList<Node> nodes = new ArrayList<Node>();
|
||||
for ( int i = 0; i < 4; i++ ) {
|
||||
Node n = new Node();
|
||||
n.setName( "Node " + i );
|
||||
n.setTour( tour );
|
||||
n.setRoute( route );
|
||||
nodes.add( n );
|
||||
}
|
||||
|
||||
tour.setNodes( new HashSet<>( nodes ) );
|
||||
route.setNodes( new HashSet<>( Arrays.asList( nodes.get( 0 ), nodes.get( 1 ), nodes.get( 2 ) ) ) );
|
||||
|
||||
Vehicle vehicle = new Vehicle();
|
||||
vehicle.setName( "Car" );
|
||||
route.setVehicles( new HashSet<>( Arrays.asList( vehicle ) ) );
|
||||
vehicle.setRoute( route );
|
||||
|
||||
Transport $0to1 = new Transport();
|
||||
$0to1.setName( "Transport 0 -> 1" );
|
||||
$0to1.setPickupNode( nodes.get( 0 ) );
|
||||
$0to1.setDeliveryNode( nodes.get( 1 ) );
|
||||
$0to1.setVehicle( vehicle );
|
||||
|
||||
Transport $1to2 = new Transport();
|
||||
$1to2.setName( "Transport 1 -> 2" );
|
||||
$1to2.setPickupNode( nodes.get( 1 ) );
|
||||
$1to2.setDeliveryNode( nodes.get( 2 ) );
|
||||
$1to2.setVehicle( vehicle );
|
||||
|
||||
vehicle.setTransports( new HashSet<>( Arrays.asList( $0to1, $1to2 ) ) );
|
||||
|
||||
scope.inTransaction(
|
||||
session ->
|
||||
session.persist( tour )
|
||||
);
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.cascade.circle">
|
||||
<hibernate-mapping package="org.hibernate.orm.test.cascade.circle">
|
||||
|
||||
<class name="Route" table="HB_Route">
|
||||
|
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* 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.cascade.circle;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
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.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* The test case uses the following model:
|
||||
* <p>
|
||||
* <- ->
|
||||
* -- (N : 0,1) -- Tour
|
||||
* | <- ->
|
||||
* | -- (1 : N) -- (pickup) ----
|
||||
* -> | | |
|
||||
* Route -- (1 : N) - Node Transport
|
||||
* | | <- -> | |
|
||||
* | -- (1 : N) -- (delivery) -- |
|
||||
* | |
|
||||
* | -> -> |
|
||||
* -------- (1 : N) ---- Vehicle--(1 : N)------------
|
||||
* <p>
|
||||
* Arrows indicate the direction of cascade-merge.
|
||||
* <p/>
|
||||
* I believe it reproduces the following issue:
|
||||
* http://opensource.atlassian.com/projects/hibernate/browse/HHH-3544
|
||||
*
|
||||
* @author Gail Badner (based on original model provided by Pavol Zibrita)
|
||||
*/
|
||||
@DomainModel(
|
||||
xmlMappings = {
|
||||
"org/hibernate/orm/test/cascade/circle/CascadeMergeToChildBeforeParent.hbm.xml"
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@ServiceRegistry(
|
||||
settings = @ServiceRegistry.Setting(name = Environment.CHECK_NULLABILITY, value = "true")
|
||||
)
|
||||
public class CascadeMergeToChildBeforeParentTest {
|
||||
|
||||
@AfterEach
|
||||
public void cleanupTest(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete from Transport" );
|
||||
session.createQuery( "delete from Tour" );
|
||||
session.createQuery( "delete from Node" );
|
||||
session.createQuery( "delete from Route" );
|
||||
session.createQuery( "delete from Vehicle" );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMerge(SessionFactoryScope scope) {
|
||||
Route r = new Route();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
r.setName( "routeA" );
|
||||
session.save( r );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Route route = session.get( Route.class, r.getRouteID() );
|
||||
|
||||
route.setTransientField( "sfnaouisrbn" );
|
||||
|
||||
Tour tour = new Tour();
|
||||
tour.setName( "tourB" );
|
||||
|
||||
Node pickupNode = new Node();
|
||||
pickupNode.setName( "pickupNodeB" );
|
||||
|
||||
Node deliveryNode = new Node();
|
||||
deliveryNode.setName( "deliveryNodeB" );
|
||||
|
||||
pickupNode.setRoute( route );
|
||||
pickupNode.setTour( tour );
|
||||
pickupNode.setTransientField( "pickup node aaaaaaaaaaa" );
|
||||
|
||||
deliveryNode.setRoute( route );
|
||||
deliveryNode.setTour( tour );
|
||||
deliveryNode.setTransientField( "delivery node aaaaaaaaa" );
|
||||
|
||||
tour.getNodes().add( pickupNode );
|
||||
tour.getNodes().add( deliveryNode );
|
||||
|
||||
route.getNodes().add( pickupNode );
|
||||
route.getNodes().add( deliveryNode );
|
||||
|
||||
session.merge( route );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeTransientChildBeforeTransientParent(SessionFactoryScope scope) {
|
||||
// This test fails because the merge algorithm tries to save a
|
||||
// transient child (transport) before cascade-merge gets its
|
||||
// transient parent (vehicle); merge does not cascade from the
|
||||
// child to the parent.
|
||||
|
||||
Route r = new Route();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
r.setName( "routeA" );
|
||||
|
||||
session.save( r );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Route route = session.get( Route.class, r.getRouteID() );
|
||||
|
||||
route.setTransientField( "sfnaouisrbn" );
|
||||
|
||||
Tour tour = new Tour();
|
||||
tour.setName( "tourB" );
|
||||
|
||||
Transport transport = new Transport();
|
||||
transport.setName( "transportB" );
|
||||
|
||||
Node pickupNode = new Node();
|
||||
pickupNode.setName( "pickupNodeB" );
|
||||
|
||||
Node deliveryNode = new Node();
|
||||
deliveryNode.setName( "deliveryNodeB" );
|
||||
|
||||
Vehicle vehicle = new Vehicle();
|
||||
vehicle.setName( "vehicleB" );
|
||||
|
||||
pickupNode.setRoute( route );
|
||||
pickupNode.setTour( tour );
|
||||
pickupNode.getPickupTransports().add( transport );
|
||||
pickupNode.setTransientField( "pickup node aaaaaaaaaaa" );
|
||||
|
||||
deliveryNode.setRoute( route );
|
||||
deliveryNode.setTour( tour );
|
||||
deliveryNode.getDeliveryTransports().add( transport );
|
||||
deliveryNode.setTransientField( "delivery node aaaaaaaaa" );
|
||||
|
||||
tour.getNodes().add( pickupNode );
|
||||
tour.getNodes().add( deliveryNode );
|
||||
|
||||
route.getNodes().add( pickupNode );
|
||||
route.getNodes().add( deliveryNode );
|
||||
route.getVehicles().add( vehicle );
|
||||
|
||||
transport.setPickupNode( pickupNode );
|
||||
transport.setDeliveryNode( deliveryNode );
|
||||
transport.setVehicle( vehicle );
|
||||
transport.setTransientField( "aaaaaaaaaaaaaa" );
|
||||
|
||||
vehicle.getTransports().add( transport );
|
||||
vehicle.setTransientField( "anewvalue" );
|
||||
vehicle.setRoute( route );
|
||||
|
||||
session.merge( route );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeData3Nodes(SessionFactoryScope scope) {
|
||||
|
||||
Route r = new Route();
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
r.setName( "routeA" );
|
||||
|
||||
session.save( r );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Route route = session.get( Route.class, r.getRouteID() );
|
||||
|
||||
route.setTransientField( "sfnaouisrbn" );
|
||||
|
||||
Tour tour = new Tour();
|
||||
tour.setName( "tourB" );
|
||||
|
||||
Transport transport1 = new Transport();
|
||||
transport1.setName( "TRANSPORT1" );
|
||||
|
||||
Transport transport2 = new Transport();
|
||||
transport2.setName( "TRANSPORT2" );
|
||||
|
||||
Node node1 = new Node();
|
||||
node1.setName( "NODE1" );
|
||||
|
||||
Node node2 = new Node();
|
||||
node2.setName( "NODE2" );
|
||||
|
||||
Node node3 = new Node();
|
||||
node3.setName( "NODE3" );
|
||||
|
||||
Vehicle vehicle = new Vehicle();
|
||||
vehicle.setName( "vehicleB" );
|
||||
|
||||
node1.setRoute( route );
|
||||
node1.setTour( tour );
|
||||
node1.getPickupTransports().add( transport1 );
|
||||
node1.setTransientField( "node 1" );
|
||||
|
||||
node2.setRoute( route );
|
||||
node2.setTour( tour );
|
||||
node2.getDeliveryTransports().add( transport1 );
|
||||
node2.getPickupTransports().add( transport2 );
|
||||
node2.setTransientField( "node 2" );
|
||||
|
||||
node3.setRoute( route );
|
||||
node3.setTour( tour );
|
||||
node3.getDeliveryTransports().add( transport2 );
|
||||
node3.setTransientField( "node 3" );
|
||||
|
||||
tour.getNodes().add( node1 );
|
||||
tour.getNodes().add( node2 );
|
||||
tour.getNodes().add( node3 );
|
||||
|
||||
route.getNodes().add( node1 );
|
||||
route.getNodes().add( node2 );
|
||||
route.getNodes().add( node3 );
|
||||
route.getVehicles().add( vehicle );
|
||||
|
||||
transport1.setPickupNode( node1 );
|
||||
transport1.setDeliveryNode( node2 );
|
||||
transport1.setVehicle( vehicle );
|
||||
transport1.setTransientField( "aaaaaaaaaaaaaa" );
|
||||
|
||||
transport2.setPickupNode( node2 );
|
||||
transport2.setDeliveryNode( node3 );
|
||||
transport2.setVehicle( vehicle );
|
||||
transport2.setTransientField( "bbbbbbbbbbbbb" );
|
||||
|
||||
vehicle.getTransports().add( transport1 );
|
||||
vehicle.getTransports().add( transport2 );
|
||||
vehicle.setTransientField( "anewvalue" );
|
||||
vehicle.setRoute( route );
|
||||
|
||||
session.merge( route );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.cascade.circle">
|
||||
<hibernate-mapping package="org.hibernate.orm.test.cascade.circle">
|
||||
|
||||
<class name="Route" table="HB_Route">
|
||||
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.cascade.circle;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@DomainModel(
|
||||
xmlMappings = {
|
||||
"org/hibernate/orm/test/cascade/circle/MultiPathCircleCascadeDelayedInsert.hbm.xml"
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@ServiceRegistry(
|
||||
settings = {
|
||||
@ServiceRegistry.Setting(name = Environment.GENERATE_STATISTICS, value = "true"),
|
||||
@ServiceRegistry.Setting(name = Environment.STATEMENT_BATCH_SIZE, value = "0"),
|
||||
@ServiceRegistry.Setting(name = Environment.CHECK_NULLABILITY, value = "false")
|
||||
}
|
||||
)
|
||||
public class MultiPathCircleCascadeCheckNullFalseDelayedInsertTest extends AbstractMultiPathCircleCascadeTest {
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.cascade.circle;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@DomainModel(
|
||||
xmlMappings = {
|
||||
"org/hibernate/orm/test/cascade/circle/MultiPathCircleCascadeDelayedInsert.hbm.xml"
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@ServiceRegistry(
|
||||
settings = {
|
||||
@ServiceRegistry.Setting(name = Environment.GENERATE_STATISTICS, value = "true"),
|
||||
@ServiceRegistry.Setting(name = Environment.STATEMENT_BATCH_SIZE, value = "0"),
|
||||
@ServiceRegistry.Setting(name = Environment.CHECK_NULLABILITY, value = "true")
|
||||
}
|
||||
)
|
||||
public class MultiPathCircleCascadeCheckNullTrueDelayedInsertTest extends AbstractMultiPathCircleCascadeTest {
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.cascade.circle;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@DomainModel(
|
||||
xmlMappings = {
|
||||
"org/hibernate/orm/test/cascade/circle/MultiPathCircleCascade.hbm.xml"
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@ServiceRegistry(
|
||||
settings = {
|
||||
@ServiceRegistry.Setting(name = Environment.GENERATE_STATISTICS, value = "true"),
|
||||
@ServiceRegistry.Setting(name = Environment.STATEMENT_BATCH_SIZE, value = "0"),
|
||||
@ServiceRegistry.Setting(name = Environment.CHECK_NULLABILITY, value = "false")
|
||||
}
|
||||
)
|
||||
public class MultiPathCircleCascadeCheckNullibilityFalseTest extends AbstractMultiPathCircleCascadeTest {
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.cascade.circle;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@DomainModel(
|
||||
xmlMappings = {
|
||||
"org/hibernate/orm/test/cascade/circle/MultiPathCircleCascade.hbm.xml"
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@ServiceRegistry(
|
||||
settings = {
|
||||
@ServiceRegistry.Setting(name = Environment.GENERATE_STATISTICS, value = "true"),
|
||||
@ServiceRegistry.Setting(name = Environment.STATEMENT_BATCH_SIZE, value = "0"),
|
||||
@ServiceRegistry.Setting(name = Environment.CHECK_NULLABILITY, value = "true")
|
||||
}
|
||||
)
|
||||
public class MultiPathCircleCascadeCheckNullibilityTrueTest extends AbstractMultiPathCircleCascadeTest {
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.cascade.circle">
|
||||
<hibernate-mapping package="org.hibernate.orm.test.cascade.circle">
|
||||
|
||||
<class name="Route" table="HB_Route">
|
||||
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.cascade.circle;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@DomainModel(
|
||||
xmlMappings = {
|
||||
"org/hibernate/orm/test/cascade/circle/MultiPathCircleCascadeDelayedInsert.hbm.xml"
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@ServiceRegistry(
|
||||
settings = {
|
||||
@ServiceRegistry.Setting(name = Environment.GENERATE_STATISTICS, value = "true"),
|
||||
@ServiceRegistry.Setting(name = Environment.STATEMENT_BATCH_SIZE, value = "0"),
|
||||
}
|
||||
)
|
||||
public class MultiPathCircleCascadeDelayedInsertTest extends AbstractMultiPathCircleCascadeTest {
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.cascade.circle;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
|
||||
/**
|
||||
* The test case uses the following model:
|
||||
* <p>
|
||||
* <- ->
|
||||
* -- (N : 0,1) -- Tour
|
||||
* | <- ->
|
||||
* | -- (1 : N) -- (pickup) ----
|
||||
* -> | | |
|
||||
* Route -- (1 : N) -- Node Transport
|
||||
* | <- -> |
|
||||
* -- (1 : N) -- (delivery) --
|
||||
* <p>
|
||||
* Arrows indicate the direction of cascade-merge, cascade-save, and cascade-save-or-update
|
||||
* <p>
|
||||
* It reproduced the following issues:
|
||||
* http://opensource.atlassian.com/projects/hibernate/browse/HHH-3046
|
||||
* http://opensource.atlassian.com/projects/hibernate/browse/HHH-3810
|
||||
* <p/>
|
||||
* This tests that cascades are done properly from each entity.
|
||||
*
|
||||
* @author Pavol Zibrita, Gail Badner
|
||||
*/
|
||||
@DomainModel(
|
||||
xmlMappings = {
|
||||
"org/hibernate/orm/test/cascade/circle/MultiPathCircleCascade.hbm.xml"
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@ServiceRegistry(
|
||||
settings = {
|
||||
@ServiceRegistry.Setting(name = Environment.GENERATE_STATISTICS, value = "true"),
|
||||
@ServiceRegistry.Setting(name = Environment.STATEMENT_BATCH_SIZE, value = "0"),
|
||||
}
|
||||
)
|
||||
public class MultiPathCircleCascadeTest extends AbstractMultiPathCircleCascadeTest {
|
||||
}
|
@ -4,11 +4,9 @@
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
//$Id: $
|
||||
package org.hibernate.orm.test.cascade.circle;
|
||||
|
||||
|
||||
package org.hibernate.test.cascade.circle;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
@ -41,7 +39,7 @@ public class Node {
|
||||
// @ManyToOne(targetEntity=Tour.class, cascade={CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, optional=true, fetch=FetchType.LAZY)
|
||||
// @JoinColumn(name="TOURID", nullable=true, insertable=true, updatable=true)
|
||||
private Tour tour;
|
||||
|
||||
|
||||
// @Transient
|
||||
private String transientField = "node original value";
|
||||
|
@ -6,9 +6,8 @@
|
||||
*/
|
||||
|
||||
//$Id: $
|
||||
package org.hibernate.orm.test.cascade.circle;
|
||||
|
||||
|
||||
package org.hibernate.test.cascade.circle;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
@ -7,7 +7,8 @@
|
||||
|
||||
//$Id: $
|
||||
|
||||
package org.hibernate.test.cascade.circle;
|
||||
package org.hibernate.orm.test.cascade.circle;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
@ -6,11 +6,7 @@
|
||||
*/
|
||||
|
||||
//$Id: $
|
||||
|
||||
|
||||
package org.hibernate.test.cascade.circle;
|
||||
|
||||
|
||||
package org.hibernate.orm.test.cascade.circle;
|
||||
|
||||
public class Transport {
|
||||
|
||||
@ -34,7 +30,7 @@ public class Transport {
|
||||
private Node deliveryNode = null;
|
||||
|
||||
private Vehicle vehicle;
|
||||
|
||||
|
||||
// @Transient
|
||||
private String transientField = "transport original value";
|
||||
|
@ -7,8 +7,8 @@
|
||||
|
||||
//$Id: $
|
||||
|
||||
package org.hibernate.orm.test.cascade.circle;
|
||||
|
||||
package org.hibernate.test.cascade.circle;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
@ -1,164 +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.cascade.circle;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The test case uses the following model:
|
||||
*
|
||||
* <- ->
|
||||
* -- (N : 0,1) -- Tour
|
||||
* | <- ->
|
||||
* | -- (1 : N) -- (pickup) ----
|
||||
* <- -> | | |
|
||||
* Route -- (1 : N) -- Node Transport
|
||||
* | <- -> |
|
||||
* -- (1 : N) -- (delivery) --
|
||||
*
|
||||
* Arrows indicate the direction of cascade-merge, cascade-save, cascade-refresh and cascade-save-or-update
|
||||
*
|
||||
* It reproduces the following issues:
|
||||
* https://hibernate.atlassian.net/browse/HHH-9512
|
||||
* <p/>
|
||||
* This tests that cascades are done properly from each entity.
|
||||
*
|
||||
* @author Alex Belyaev (based on code by Pavol Zibrita and Gail Badner)
|
||||
*/
|
||||
public class CascadeManagedAndTransientTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public String[] getMappings() {
|
||||
return new String[] {
|
||||
"cascade/circle/CascadeManagedAndTransient.hbm.xml"
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Configuration cfg) {
|
||||
super.configure( cfg );
|
||||
cfg.setProperty( Environment.CHECK_NULLABILITY, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanupTest() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
s.createQuery( "delete from Transport" );
|
||||
s.createQuery( "delete from Tour" );
|
||||
s.createQuery( "delete from Node" );
|
||||
s.createQuery( "delete from Route" );
|
||||
s.createQuery( "delete from Vehicle" );
|
||||
}
|
||||
|
||||
private void checkNewVehicle(Vehicle newVehicle) {
|
||||
assertEquals("Bus", newVehicle.getName());
|
||||
assertEquals(1, newVehicle.getTransports().size());
|
||||
Transport t = (Transport) newVehicle.getTransports().iterator().next();
|
||||
assertEquals("Transport 2 -> 3", t.getName());
|
||||
assertEquals("Node 2", t.getPickupNode().getName());
|
||||
assertEquals("Node 3", t.getDeliveryNode().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttachedChildInMerge() {
|
||||
fillInitialData();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Route route = (Route) s.createQuery("FROM Route WHERE name = :name").setParameter("name", "Route 1").uniqueResult();
|
||||
Node n2 = (Node) s.createQuery("FROM Node WHERE name = :name").setParameter("name", "Node 2").uniqueResult();
|
||||
Node n3 = (Node) s.createQuery("FROM Node WHERE name = :name").setParameter("name", "Node 3").uniqueResult();
|
||||
|
||||
Vehicle vehicle = new Vehicle();
|
||||
vehicle.setName("Bus");
|
||||
vehicle.setRoute(route);
|
||||
|
||||
Transport $2to3 = new Transport();
|
||||
$2to3.setName("Transport 2 -> 3");
|
||||
$2to3.setPickupNode(n2); n2.getPickupTransports().add($2to3);
|
||||
$2to3.setDeliveryNode(n3); n3.getDeliveryTransports().add($2to3);
|
||||
$2to3.setVehicle(vehicle);
|
||||
|
||||
vehicle.setTransports(new HashSet<Transport>(Arrays.asList($2to3)));
|
||||
|
||||
// Try to save graph of transient entities (vehicle, transport) which contains attached entities (node2, node3)
|
||||
Vehicle managedVehicle = (Vehicle) s.merge(vehicle);
|
||||
checkNewVehicle(managedVehicle);
|
||||
|
||||
s.flush();
|
||||
s.clear();
|
||||
|
||||
assertEquals(3, s.createQuery("FROM Transport").list().size());
|
||||
assertEquals(2, s.createQuery("FROM Vehicle").list().size());
|
||||
assertEquals(4, s.createQuery("FROM Node").list().size());
|
||||
|
||||
Vehicle newVehicle = (Vehicle) s.createQuery("FROM Vehicle WHERE name = :name").setParameter("name", "Bus").uniqueResult();
|
||||
checkNewVehicle(newVehicle);
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
private void fillInitialData() {
|
||||
Tour tour = new Tour();
|
||||
tour.setName("Tour 1");
|
||||
|
||||
Route route = new Route();
|
||||
route.setName("Route 1");
|
||||
|
||||
ArrayList<Node> nodes = new ArrayList<Node>();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Node n = new Node();
|
||||
n.setName("Node " + i);
|
||||
n.setTour(tour);
|
||||
n.setRoute(route);
|
||||
nodes.add(n);
|
||||
}
|
||||
|
||||
tour.setNodes(new HashSet<Node>(nodes));
|
||||
route.setNodes(new HashSet<Node>(Arrays.asList(nodes.get(0), nodes.get(1), nodes.get(2))));
|
||||
|
||||
Vehicle vehicle = new Vehicle();
|
||||
vehicle.setName("Car");
|
||||
route.setVehicles(new HashSet<Vehicle>(Arrays.asList(vehicle)));
|
||||
vehicle.setRoute(route);
|
||||
|
||||
Transport $0to1 = new Transport();
|
||||
$0to1.setName("Transport 0 -> 1");
|
||||
$0to1.setPickupNode(nodes.get(0));
|
||||
$0to1.setDeliveryNode(nodes.get(1));
|
||||
$0to1.setVehicle(vehicle);
|
||||
|
||||
Transport $1to2 = new Transport();
|
||||
$1to2.setName("Transport 1 -> 2");
|
||||
$1to2.setPickupNode(nodes.get(1));
|
||||
$1to2.setDeliveryNode(nodes.get(2));
|
||||
$1to2.setVehicle(vehicle);
|
||||
|
||||
vehicle.setTransports(new HashSet<Transport>(Arrays.asList($0to1, $1to2)));
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
s.persist(tour);
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
@ -1,268 +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.cascade.circle;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* The test case uses the following model:
|
||||
*
|
||||
* <- ->
|
||||
* -- (N : 0,1) -- Tour
|
||||
* | <- ->
|
||||
* | -- (1 : N) -- (pickup) ----
|
||||
* -> | | |
|
||||
* Route -- (1 : N) - Node Transport
|
||||
* | | <- -> | |
|
||||
* | -- (1 : N) -- (delivery) -- |
|
||||
* | |
|
||||
* | -> -> |
|
||||
* -------- (1 : N) ---- Vehicle--(1 : N)------------
|
||||
*
|
||||
* Arrows indicate the direction of cascade-merge.
|
||||
* <p/>
|
||||
* I believe it reproduces the following issue:
|
||||
* http://opensource.atlassian.com/projects/hibernate/browse/HHH-3544
|
||||
*
|
||||
* @author Gail Badner (based on original model provided by Pavol Zibrita)
|
||||
*/
|
||||
public class CascadeMergeToChildBeforeParentTest extends BaseCoreFunctionalTestCase {
|
||||
@Override
|
||||
public String[] getMappings() {
|
||||
return new String[] {
|
||||
"cascade/circle/CascadeMergeToChildBeforeParent.hbm.xml"
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Configuration cfg) {
|
||||
super.configure( cfg );
|
||||
cfg.setProperty( Environment.CHECK_NULLABILITY, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanupTest() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
s.createQuery( "delete from Transport" );
|
||||
s.createQuery( "delete from Tour" );
|
||||
s.createQuery( "delete from Node" );
|
||||
s.createQuery( "delete from Route" );
|
||||
s.createQuery( "delete from Vehicle" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMerge() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Route route = new Route();
|
||||
route.setName( "routeA" );
|
||||
|
||||
s.save( route );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
route = (Route) s.get( Route.class, route.getRouteID() );
|
||||
|
||||
route.setTransientField( new String( "sfnaouisrbn" ) );
|
||||
|
||||
Tour tour = new Tour();
|
||||
tour.setName( "tourB" );
|
||||
|
||||
Node pickupNode = new Node();
|
||||
pickupNode.setName( "pickupNodeB" );
|
||||
|
||||
Node deliveryNode = new Node();
|
||||
deliveryNode.setName( "deliveryNodeB" );
|
||||
|
||||
pickupNode.setRoute( route );
|
||||
pickupNode.setTour( tour );
|
||||
pickupNode.setTransientField( "pickup node aaaaaaaaaaa" );
|
||||
|
||||
deliveryNode.setRoute( route );
|
||||
deliveryNode.setTour( tour );
|
||||
deliveryNode.setTransientField( "delivery node aaaaaaaaa" );
|
||||
|
||||
tour.getNodes().add( pickupNode );
|
||||
tour.getNodes().add( deliveryNode );
|
||||
|
||||
route.getNodes().add( pickupNode );
|
||||
route.getNodes().add( deliveryNode );
|
||||
|
||||
Route mergedRoute = (Route) s.merge( route );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeTransientChildBeforeTransientParent() {
|
||||
// This test fails because the merge algorithm tries to save a
|
||||
// transient child (transport) before cascade-merge gets its
|
||||
// transient parent (vehicle); merge does not cascade from the
|
||||
// child to the parent.
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Route route = new Route();
|
||||
route.setName( "routeA" );
|
||||
|
||||
s.save( route );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
route = (Route) s.get( Route.class, route.getRouteID() );
|
||||
|
||||
route.setTransientField( new String( "sfnaouisrbn" ) );
|
||||
|
||||
Tour tour = new Tour();
|
||||
tour.setName( "tourB" );
|
||||
|
||||
Transport transport = new Transport();
|
||||
transport.setName( "transportB" );
|
||||
|
||||
Node pickupNode = new Node();
|
||||
pickupNode.setName( "pickupNodeB" );
|
||||
|
||||
Node deliveryNode = new Node();
|
||||
deliveryNode.setName( "deliveryNodeB" );
|
||||
|
||||
Vehicle vehicle = new Vehicle();
|
||||
vehicle.setName( "vehicleB" );
|
||||
|
||||
pickupNode.setRoute( route );
|
||||
pickupNode.setTour( tour );
|
||||
pickupNode.getPickupTransports().add( transport );
|
||||
pickupNode.setTransientField( "pickup node aaaaaaaaaaa" );
|
||||
|
||||
deliveryNode.setRoute( route );
|
||||
deliveryNode.setTour( tour );
|
||||
deliveryNode.getDeliveryTransports().add( transport );
|
||||
deliveryNode.setTransientField( "delivery node aaaaaaaaa" );
|
||||
|
||||
tour.getNodes().add( pickupNode );
|
||||
tour.getNodes().add( deliveryNode );
|
||||
|
||||
route.getNodes().add( pickupNode );
|
||||
route.getNodes().add( deliveryNode );
|
||||
route.getVehicles().add( vehicle );
|
||||
|
||||
transport.setPickupNode( pickupNode );
|
||||
transport.setDeliveryNode( deliveryNode );
|
||||
transport.setVehicle( vehicle );
|
||||
transport.setTransientField( "aaaaaaaaaaaaaa" );
|
||||
|
||||
vehicle.getTransports().add( transport );
|
||||
vehicle.setTransientField( "anewvalue" );
|
||||
vehicle.setRoute( route );
|
||||
|
||||
Route mergedRoute = (Route) s.merge( route );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeData3Nodes() {
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Route route = new Route();
|
||||
route.setName( "routeA" );
|
||||
|
||||
s.save( route );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
route = (Route) s.get( Route.class, route.getRouteID() );
|
||||
|
||||
route.setTransientField( new String( "sfnaouisrbn" ) );
|
||||
|
||||
Tour tour = new Tour();
|
||||
tour.setName( "tourB" );
|
||||
|
||||
Transport transport1 = new Transport();
|
||||
transport1.setName( "TRANSPORT1" );
|
||||
|
||||
Transport transport2 = new Transport();
|
||||
transport2.setName( "TRANSPORT2" );
|
||||
|
||||
Node node1 = new Node();
|
||||
node1.setName( "NODE1" );
|
||||
|
||||
Node node2 = new Node();
|
||||
node2.setName( "NODE2" );
|
||||
|
||||
Node node3 = new Node();
|
||||
node3.setName( "NODE3" );
|
||||
|
||||
Vehicle vehicle = new Vehicle();
|
||||
vehicle.setName( "vehicleB" );
|
||||
|
||||
node1.setRoute( route );
|
||||
node1.setTour( tour );
|
||||
node1.getPickupTransports().add( transport1 );
|
||||
node1.setTransientField( "node 1" );
|
||||
|
||||
node2.setRoute( route );
|
||||
node2.setTour( tour );
|
||||
node2.getDeliveryTransports().add( transport1 );
|
||||
node2.getPickupTransports().add( transport2 );
|
||||
node2.setTransientField( "node 2" );
|
||||
|
||||
node3.setRoute( route );
|
||||
node3.setTour( tour );
|
||||
node3.getDeliveryTransports().add( transport2 );
|
||||
node3.setTransientField( "node 3" );
|
||||
|
||||
tour.getNodes().add( node1 );
|
||||
tour.getNodes().add( node2 );
|
||||
tour.getNodes().add( node3 );
|
||||
|
||||
route.getNodes().add( node1 );
|
||||
route.getNodes().add( node2 );
|
||||
route.getNodes().add( node3 );
|
||||
route.getVehicles().add( vehicle );
|
||||
|
||||
transport1.setPickupNode( node1 );
|
||||
transport1.setDeliveryNode( node2 );
|
||||
transport1.setVehicle( vehicle );
|
||||
transport1.setTransientField( "aaaaaaaaaaaaaa" );
|
||||
|
||||
transport2.setPickupNode( node2 );
|
||||
transport2.setDeliveryNode( node3 );
|
||||
transport2.setVehicle( vehicle );
|
||||
transport2.setTransientField( "bbbbbbbbbbbbb" );
|
||||
|
||||
vehicle.getTransports().add( transport1 );
|
||||
vehicle.getTransports().add( transport2 );
|
||||
vehicle.setTransientField( "anewvalue" );
|
||||
vehicle.setRoute( route );
|
||||
|
||||
Route mergedRoute = (Route) s.merge( route );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
}
|
@ -1,21 +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.cascade.circle;
|
||||
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class MultiPathCircleCascadeCheckNullFalseDelayedInsertTest extends MultiPathCircleCascadeDelayedInsertTest {
|
||||
@Override
|
||||
public void configure(Configuration cfg) {
|
||||
super.configure( cfg );
|
||||
cfg.setProperty( Environment.CHECK_NULLABILITY, "false" );
|
||||
}
|
||||
}
|
@ -1,21 +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.cascade.circle;
|
||||
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class MultiPathCircleCascadeCheckNullTrueDelayedInsertTest extends MultiPathCircleCascadeDelayedInsertTest {
|
||||
@Override
|
||||
public void configure(Configuration cfg) {
|
||||
super.configure( cfg );
|
||||
cfg.setProperty( Environment.CHECK_NULLABILITY, "true" );
|
||||
}
|
||||
}
|
@ -1,21 +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.cascade.circle;
|
||||
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class MultiPathCircleCascadeCheckNullibilityFalseTest extends MultiPathCircleCascadeTest {
|
||||
@Override
|
||||
public void configure(Configuration cfg) {
|
||||
super.configure( cfg );
|
||||
cfg.setProperty( Environment.CHECK_NULLABILITY, "false" );
|
||||
}
|
||||
}
|
@ -1,21 +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.cascade.circle;
|
||||
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class MultiPathCircleCascadeCheckNullibilityTrueTest extends MultiPathCircleCascadeTest {
|
||||
@Override
|
||||
public void configure(Configuration cfg) {
|
||||
super.configure( cfg );
|
||||
cfg.setProperty( Environment.CHECK_NULLABILITY, "true" );
|
||||
}
|
||||
}
|
@ -1,20 +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.cascade.circle;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class MultiPathCircleCascadeDelayedInsertTest extends MultiPathCircleCascadeTest {
|
||||
@Override
|
||||
public String[] getMappings() {
|
||||
return new String[] {
|
||||
"cascade/circle/MultiPathCircleCascadeDelayedInsert.hbm.xml"
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -1,725 +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.cascade.circle;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.PropertyValueException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.TransientPropertyValueException;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* The test case uses the following model:
|
||||
*
|
||||
* <- ->
|
||||
* -- (N : 0,1) -- Tour
|
||||
* | <- ->
|
||||
* | -- (1 : N) -- (pickup) ----
|
||||
* -> | | |
|
||||
* Route -- (1 : N) -- Node Transport
|
||||
* | <- -> |
|
||||
* -- (1 : N) -- (delivery) --
|
||||
*
|
||||
* Arrows indicate the direction of cascade-merge, cascade-save, and cascade-save-or-update
|
||||
*
|
||||
* It reproduced the following issues:
|
||||
* http://opensource.atlassian.com/projects/hibernate/browse/HHH-3046
|
||||
* http://opensource.atlassian.com/projects/hibernate/browse/HHH-3810
|
||||
* <p/>
|
||||
* This tests that cascades are done properly from each entity.
|
||||
*
|
||||
* @author Pavol Zibrita, Gail Badner
|
||||
*/
|
||||
public class MultiPathCircleCascadeTest extends BaseCoreFunctionalTestCase {
|
||||
private static interface EntityOperation {
|
||||
boolean isLegacy();
|
||||
Object doEntityOperation(Object entity, Session s);
|
||||
}
|
||||
private static EntityOperation MERGE_OPERATION =
|
||||
new EntityOperation() {
|
||||
@Override
|
||||
public boolean isLegacy() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public Object doEntityOperation(Object entity, Session s) {
|
||||
return s.merge( entity );
|
||||
}
|
||||
};
|
||||
private static EntityOperation SAVE_OPERATION =
|
||||
new EntityOperation() {
|
||||
@Override
|
||||
public boolean isLegacy() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public Object doEntityOperation(Object entity, Session s) {
|
||||
s.save( entity );
|
||||
return entity;
|
||||
}
|
||||
};
|
||||
private static EntityOperation SAVE_UPDATE_OPERATION =
|
||||
new EntityOperation() {
|
||||
@Override
|
||||
public boolean isLegacy() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public Object doEntityOperation(Object entity, Session s) {
|
||||
s.saveOrUpdate( entity );
|
||||
return entity;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void configure(Configuration cfg) {
|
||||
cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
|
||||
cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "0" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getMappings() {
|
||||
return new String[] {
|
||||
"cascade/circle/MultiPathCircleCascade.hbm.xml"
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeEntityWithNonNullableTransientEntity() {
|
||||
testEntityWithNonNullableTransientEntity( MERGE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveEntityWithNonNullableTransientEntity() {
|
||||
testEntityWithNonNullableTransientEntity( SAVE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveUpdateEntityWithNonNullableTransientEntity() {
|
||||
testEntityWithNonNullableTransientEntity( SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
private void testEntityWithNonNullableTransientEntity(EntityOperation operation) {
|
||||
|
||||
Route route = getUpdatedDetachedEntity();
|
||||
|
||||
Node node = (Node) route.getNodes().iterator().next();
|
||||
route.getNodes().remove( node );
|
||||
|
||||
Route routeNew = new Route();
|
||||
routeNew.setName( "new route" );
|
||||
routeNew.getNodes().add( node );
|
||||
node.setRoute( routeNew );
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
try {
|
||||
operation.doEntityOperation( node, s );
|
||||
s.getTransaction().commit();
|
||||
fail( "should have thrown an exception" );
|
||||
}
|
||||
catch (Exception ex) {
|
||||
checkExceptionFromNullValueForNonNullable(
|
||||
ex,
|
||||
((SessionImplementor) s).getFactory().getSettings().isCheckNullability(),
|
||||
false,
|
||||
operation.isLegacy()
|
||||
);
|
||||
}
|
||||
finally {
|
||||
s.getTransaction().rollback();
|
||||
s.close();
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeEntityWithNonNullableEntityNull() {
|
||||
testEntityWithNonNullableEntityNull( MERGE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveEntityWithNonNullableEntityNull() {
|
||||
testEntityWithNonNullableEntityNull( SAVE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveUpdateEntityWithNonNullableEntityNull() {
|
||||
testEntityWithNonNullableEntityNull( SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
private void testEntityWithNonNullableEntityNull(EntityOperation operation) {
|
||||
Route route = getUpdatedDetachedEntity();
|
||||
|
||||
Node node = (Node) route.getNodes().iterator().next();
|
||||
route.getNodes().remove( node );
|
||||
node.setRoute( null );
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
try {
|
||||
operation.doEntityOperation( node, s );
|
||||
s.getTransaction().commit();
|
||||
fail( "should have thrown an exception" );
|
||||
}
|
||||
catch (Exception ex) {
|
||||
checkExceptionFromNullValueForNonNullable(
|
||||
ex,
|
||||
((SessionImplementor) s).getFactory().getSettings().isCheckNullability(),
|
||||
true,
|
||||
operation.isLegacy()
|
||||
);
|
||||
}
|
||||
finally {
|
||||
s.getTransaction().rollback();
|
||||
s.close();
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeEntityWithNonNullablePropSetToNull() {
|
||||
testEntityWithNonNullablePropSetToNull( MERGE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveEntityWithNonNullablePropSetToNull() {
|
||||
testEntityWithNonNullablePropSetToNull( SAVE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveUpdateEntityWithNonNullablePropSetToNull() {
|
||||
testEntityWithNonNullablePropSetToNull( SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
private void testEntityWithNonNullablePropSetToNull(EntityOperation operation) {
|
||||
Route route = getUpdatedDetachedEntity();
|
||||
Node node = (Node) route.getNodes().iterator().next();
|
||||
node.setName( null );
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
try {
|
||||
operation.doEntityOperation( route, s );
|
||||
s.getTransaction().commit();
|
||||
fail( "should have thrown an exception" );
|
||||
}
|
||||
catch (Exception ex) {
|
||||
checkExceptionFromNullValueForNonNullable(
|
||||
ex,
|
||||
((SessionImplementor) s).getFactory().getSettings().isCheckNullability(),
|
||||
true,
|
||||
operation.isLegacy()
|
||||
);
|
||||
}
|
||||
finally {
|
||||
s.getTransaction().rollback();
|
||||
s.close();
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeRoute() {
|
||||
testRoute( MERGE_OPERATION );
|
||||
}
|
||||
// skip SAVE_OPERATION since Route is not transient
|
||||
@Test
|
||||
public void testSaveUpdateRoute() {
|
||||
testRoute( SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
private void testRoute(EntityOperation operation) {
|
||||
|
||||
Route route = getUpdatedDetachedEntity();
|
||||
|
||||
clearCounts();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
operation.doEntityOperation( route, s );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
assertInsertCount( 4 );
|
||||
assertUpdateCount( 1 );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
route = (Route) s.get( Route.class, route.getRouteID() );
|
||||
checkResults( route, true );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergePickupNode() {
|
||||
testPickupNode( MERGE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSavePickupNode() {
|
||||
testPickupNode( SAVE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveUpdatePickupNode() {
|
||||
testPickupNode( SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
private void testPickupNode(EntityOperation operation) {
|
||||
|
||||
Route route = getUpdatedDetachedEntity();
|
||||
|
||||
clearCounts();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Iterator it = route.getNodes().iterator();
|
||||
Node node = (Node) it.next();
|
||||
Node pickupNode;
|
||||
if ( node.getName().equals( "pickupNodeB" ) ) {
|
||||
pickupNode = node;
|
||||
}
|
||||
else {
|
||||
node = (Node) it.next();
|
||||
assertEquals( "pickupNodeB", node.getName() );
|
||||
pickupNode = node;
|
||||
}
|
||||
|
||||
pickupNode = (Node) operation.doEntityOperation( pickupNode, s );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
assertInsertCount( 4 );
|
||||
assertUpdateCount( 0 );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
route = (Route) s.get( Route.class, route.getRouteID() );
|
||||
checkResults( route, false );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeDeliveryNode() {
|
||||
testDeliveryNode( MERGE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveDeliveryNode() {
|
||||
testDeliveryNode( SAVE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveUpdateDeliveryNode() {
|
||||
testDeliveryNode( SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
private void testDeliveryNode(EntityOperation operation) {
|
||||
|
||||
Route route = getUpdatedDetachedEntity();
|
||||
|
||||
clearCounts();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Iterator it = route.getNodes().iterator();
|
||||
Node node = (Node) it.next();
|
||||
Node deliveryNode;
|
||||
if ( node.getName().equals( "deliveryNodeB" ) ) {
|
||||
deliveryNode = node;
|
||||
}
|
||||
else {
|
||||
node = (Node) it.next();
|
||||
assertEquals( "deliveryNodeB", node.getName() );
|
||||
deliveryNode = node;
|
||||
}
|
||||
|
||||
deliveryNode = (Node) operation.doEntityOperation( deliveryNode, s );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
assertInsertCount( 4 );
|
||||
assertUpdateCount( 0 );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
route = (Route) s.get( Route.class, route.getRouteID() );
|
||||
checkResults( route, false );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeTour() {
|
||||
testTour( MERGE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveTour() {
|
||||
testTour( SAVE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveUpdateTour() {
|
||||
testTour( SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
private void testTour(EntityOperation operation) {
|
||||
|
||||
Route route = getUpdatedDetachedEntity();
|
||||
|
||||
clearCounts();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Tour tour = (Tour) operation.doEntityOperation( ((Node) route.getNodes().toArray()[0]).getTour(), s );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
assertInsertCount( 4 );
|
||||
assertUpdateCount( 0 );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
route = (Route) s.get( Route.class, route.getRouteID() );
|
||||
checkResults( route, false );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeTransport() {
|
||||
testTransport( MERGE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveTransport() {
|
||||
testTransport( SAVE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveUpdateTransport() {
|
||||
testTransport( SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
private void testTransport(EntityOperation operation) {
|
||||
|
||||
Route route = getUpdatedDetachedEntity();
|
||||
|
||||
clearCounts();
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Node node = ((Node) route.getNodes().toArray()[0]);
|
||||
Transport transport;
|
||||
if ( node.getPickupTransports().size() == 1 ) {
|
||||
transport = (Transport) node.getPickupTransports().toArray()[0];
|
||||
}
|
||||
else {
|
||||
transport = (Transport) node.getDeliveryTransports().toArray()[0];
|
||||
}
|
||||
|
||||
transport = (Transport) operation.doEntityOperation( transport, s );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
assertInsertCount( 4 );
|
||||
assertUpdateCount( 0 );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
route = (Route) s.get( Route.class, route.getRouteID() );
|
||||
checkResults( route, false );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
private Node getSimpleUpdatedDetachedEntity(){
|
||||
|
||||
Node deliveryNode = new Node();
|
||||
deliveryNode.setName( "deliveryNodeB" );
|
||||
return deliveryNode;
|
||||
}
|
||||
|
||||
private Route getUpdatedDetachedEntity() {
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Route route = new Route();
|
||||
route.setName( "routeA" );
|
||||
|
||||
s.save( route );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
route.setName( "new routeA" );
|
||||
route.setTransientField( new String( "sfnaouisrbn" ) );
|
||||
|
||||
Tour tour = new Tour();
|
||||
tour.setName( "tourB" );
|
||||
|
||||
Transport transport = new Transport();
|
||||
transport.setName( "transportB" );
|
||||
|
||||
Node pickupNode = new Node();
|
||||
pickupNode.setName( "pickupNodeB" );
|
||||
|
||||
Node deliveryNode = new Node();
|
||||
deliveryNode.setName( "deliveryNodeB" );
|
||||
|
||||
pickupNode.setRoute( route );
|
||||
pickupNode.setTour( tour );
|
||||
pickupNode.getPickupTransports().add( transport );
|
||||
pickupNode.setTransientField( "pickup node aaaaaaaaaaa" );
|
||||
|
||||
deliveryNode.setRoute( route );
|
||||
deliveryNode.setTour( tour );
|
||||
deliveryNode.getDeliveryTransports().add( transport );
|
||||
deliveryNode.setTransientField( "delivery node aaaaaaaaa" );
|
||||
|
||||
tour.getNodes().add( pickupNode );
|
||||
tour.getNodes().add( deliveryNode );
|
||||
|
||||
route.getNodes().add( pickupNode );
|
||||
route.getNodes().add( deliveryNode );
|
||||
|
||||
transport.setPickupNode( pickupNode );
|
||||
transport.setDeliveryNode( deliveryNode );
|
||||
transport.setTransientField( "aaaaaaaaaaaaaa" );
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
s.createQuery( "delete from Transport" );
|
||||
s.createQuery( "delete from Tour" );
|
||||
s.createQuery( "delete from Node" );
|
||||
s.createQuery( "delete from Route" );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
private void checkResults(Route route, boolean isRouteUpdated) {
|
||||
// since no cascaded to route, this method needs to
|
||||
// know whether route is expected to be updated
|
||||
if ( isRouteUpdated ) {
|
||||
assertEquals( "new routeA", route.getName() );
|
||||
}
|
||||
assertEquals( 2, route.getNodes().size() );
|
||||
Node deliveryNode = null;
|
||||
Node pickupNode = null;
|
||||
for ( Iterator it = route.getNodes().iterator(); it.hasNext(); ) {
|
||||
Node node = (Node) it.next();
|
||||
if ( "deliveryNodeB".equals( node.getName() ) ) {
|
||||
deliveryNode = node;
|
||||
}
|
||||
else if ( "pickupNodeB".equals( node.getName() ) ) {
|
||||
pickupNode = node;
|
||||
}
|
||||
else {
|
||||
fail( "unknown node" );
|
||||
}
|
||||
}
|
||||
assertNotNull( deliveryNode );
|
||||
assertSame( route, deliveryNode.getRoute() );
|
||||
assertEquals( 1, deliveryNode.getDeliveryTransports().size() );
|
||||
assertEquals( 0, deliveryNode.getPickupTransports().size() );
|
||||
assertNotNull( deliveryNode.getTour() );
|
||||
assertEquals( "node original value", deliveryNode.getTransientField() );
|
||||
|
||||
assertNotNull( pickupNode );
|
||||
assertSame( route, pickupNode.getRoute() );
|
||||
assertEquals( 0, pickupNode.getDeliveryTransports().size() );
|
||||
assertEquals( 1, pickupNode.getPickupTransports().size() );
|
||||
assertNotNull( pickupNode.getTour() );
|
||||
assertEquals( "node original value", pickupNode.getTransientField() );
|
||||
|
||||
assertTrue( !deliveryNode.getNodeID().equals( pickupNode.getNodeID() ) );
|
||||
assertSame( deliveryNode.getTour(), pickupNode.getTour() );
|
||||
assertSame(
|
||||
deliveryNode.getDeliveryTransports().iterator().next(),
|
||||
pickupNode.getPickupTransports().iterator().next()
|
||||
);
|
||||
|
||||
Tour tour = deliveryNode.getTour();
|
||||
Transport transport = (Transport) deliveryNode.getDeliveryTransports().iterator().next();
|
||||
|
||||
assertEquals( "tourB", tour.getName() );
|
||||
assertEquals( 2, tour.getNodes().size() );
|
||||
assertTrue( tour.getNodes().contains( deliveryNode ) );
|
||||
assertTrue( tour.getNodes().contains( pickupNode ) );
|
||||
|
||||
assertEquals( "transportB", transport.getName() );
|
||||
assertSame( deliveryNode, transport.getDeliveryNode() );
|
||||
assertSame( pickupNode, transport.getPickupNode() );
|
||||
assertEquals( "transport original value", transport.getTransientField() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeData3Nodes() {
|
||||
testData3Nodes( MERGE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveData3Nodes() {
|
||||
testData3Nodes( SAVE_OPERATION );
|
||||
}
|
||||
@Test
|
||||
public void testSaveUpdateData3Nodes() {
|
||||
testData3Nodes( SAVE_UPDATE_OPERATION );
|
||||
}
|
||||
private void testData3Nodes(EntityOperation operation) {
|
||||
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
Route route = new Route();
|
||||
route.setName( "routeA" );
|
||||
|
||||
s.save( route );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
clearCounts();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
route = (Route) s.get( Route.class, route.getRouteID() );
|
||||
//System.out.println(route);
|
||||
route.setName( "new routA" );
|
||||
|
||||
route.setTransientField( new String( "sfnaouisrbn" ) );
|
||||
|
||||
Tour tour = new Tour();
|
||||
tour.setName( "tourB" );
|
||||
|
||||
Transport transport1 = new Transport();
|
||||
transport1.setName( "TRANSPORT1" );
|
||||
|
||||
Transport transport2 = new Transport();
|
||||
transport2.setName( "TRANSPORT2" );
|
||||
|
||||
Node node1 = new Node();
|
||||
node1.setName( "NODE1" );
|
||||
|
||||
Node node2 = new Node();
|
||||
node2.setName( "NODE2" );
|
||||
|
||||
Node node3 = new Node();
|
||||
node3.setName( "NODE3" );
|
||||
|
||||
node1.setRoute( route );
|
||||
node1.setTour( tour );
|
||||
node1.getPickupTransports().add( transport1 );
|
||||
node1.setTransientField( "node 1" );
|
||||
|
||||
node2.setRoute( route );
|
||||
node2.setTour( tour );
|
||||
node2.getDeliveryTransports().add( transport1 );
|
||||
node2.getPickupTransports().add( transport2 );
|
||||
node2.setTransientField( "node 2" );
|
||||
|
||||
node3.setRoute( route );
|
||||
node3.setTour( tour );
|
||||
node3.getDeliveryTransports().add( transport2 );
|
||||
node3.setTransientField( "node 3" );
|
||||
|
||||
tour.getNodes().add( node1 );
|
||||
tour.getNodes().add( node2 );
|
||||
tour.getNodes().add( node3 );
|
||||
|
||||
route.getNodes().add( node1 );
|
||||
route.getNodes().add( node2 );
|
||||
route.getNodes().add( node3 );
|
||||
|
||||
transport1.setPickupNode( node1 );
|
||||
transport1.setDeliveryNode( node2 );
|
||||
transport1.setTransientField( "aaaaaaaaaaaaaa" );
|
||||
|
||||
transport2.setPickupNode( node2 );
|
||||
transport2.setDeliveryNode( node3 );
|
||||
transport2.setTransientField( "bbbbbbbbbbbbb" );
|
||||
|
||||
operation.doEntityOperation( route, s );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
|
||||
assertInsertCount( 6 );
|
||||
assertUpdateCount( 1 );
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
protected void checkExceptionFromNullValueForNonNullable(
|
||||
Exception ex, boolean checkNullability, boolean isNullValue, boolean isLegacy
|
||||
) {
|
||||
if ( isNullValue ) {
|
||||
if ( checkNullability ) {
|
||||
if ( isLegacy ) {
|
||||
assertTyping( PropertyValueException.class, ex );
|
||||
}
|
||||
else {
|
||||
assertTyping( PersistenceException.class, ex );
|
||||
}
|
||||
}
|
||||
else {
|
||||
assertTrue( (ex instanceof JDBCException) || (ex.getCause() instanceof JDBCException) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( isLegacy ) {
|
||||
assertTyping( TransientPropertyValueException.class, ex );
|
||||
}
|
||||
else {
|
||||
assertTyping( IllegalStateException.class, ex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void clearCounts() {
|
||||
sessionFactory().getStatistics().clear();
|
||||
}
|
||||
|
||||
protected void assertInsertCount(int expected) {
|
||||
int inserts = (int) sessionFactory().getStatistics().getEntityInsertCount();
|
||||
assertEquals( "unexpected insert count", expected, inserts );
|
||||
}
|
||||
|
||||
protected void assertUpdateCount(int expected) {
|
||||
int updates = (int) sessionFactory().getStatistics().getEntityUpdateCount();
|
||||
assertEquals( "unexpected update counts", expected, updates );
|
||||
}
|
||||
|
||||
protected void assertDeleteCount(int expected) {
|
||||
int deletes = (int) sessionFactory().getStatistics().getEntityDeleteCount();
|
||||
assertEquals( "unexpected delete counts", expected, deletes );
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user