HHH-18166 introduce hibernate.jpa.compliance.cascade
Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
ffab0d8026
commit
e3cf006e76
|
@ -731,6 +731,13 @@ public interface SessionFactoryBuilder {
|
||||||
@Deprecated( since = "6.0" )
|
@Deprecated( since = "6.0" )
|
||||||
SessionFactoryBuilder enableJpaListCompliance(boolean enabled);
|
SessionFactoryBuilder enableJpaListCompliance(boolean enabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see JpaCompliance#isJpaCascadeComplianceEnabled()
|
||||||
|
*
|
||||||
|
* @see org.hibernate.cfg.AvailableSettings#JPA_CASCADE_COMPLIANCE
|
||||||
|
*/
|
||||||
|
SessionFactoryBuilder enableJpaCascadeCompliance(boolean enabled);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see JpaCompliance#isJpaClosedComplianceEnabled()
|
* @see JpaCompliance#isJpaClosedComplianceEnabled()
|
||||||
*
|
*
|
||||||
|
|
|
@ -424,6 +424,12 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SessionFactoryBuilder enableJpaCascadeCompliance(boolean enabled) {
|
||||||
|
this.optionsBuilder.enableJpaCascadeCompliance( enabled );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SessionFactoryBuilder enableJpaClosedCompliance(boolean enabled) {
|
public SessionFactoryBuilder enableJpaClosedCompliance(boolean enabled) {
|
||||||
this.optionsBuilder.enableJpaClosedCompliance( enabled );
|
this.optionsBuilder.enableJpaClosedCompliance( enabled );
|
||||||
|
|
|
@ -1565,6 +1565,10 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
||||||
mutableJpaCompliance().setListCompliance( enabled );
|
mutableJpaCompliance().setListCompliance( enabled );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void enableJpaCascadeCompliance(boolean enabled) {
|
||||||
|
mutableJpaCompliance().setCascadeCompliance( enabled );
|
||||||
|
}
|
||||||
|
|
||||||
public void enableJpaClosedCompliance(boolean enabled) {
|
public void enableJpaClosedCompliance(boolean enabled) {
|
||||||
mutableJpaCompliance().setClosedCompliance( enabled );
|
mutableJpaCompliance().setClosedCompliance( enabled );
|
||||||
}
|
}
|
||||||
|
|
|
@ -374,6 +374,12 @@ public abstract class AbstractDelegatingSessionFactoryBuilder<T extends SessionF
|
||||||
return getThis();
|
return getThis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SessionFactoryBuilder enableJpaCascadeCompliance(boolean enabled) {
|
||||||
|
delegate.enableJpaCascadeCompliance( enabled );
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SessionFactoryBuilder enableJpaListCompliance(boolean enabled) {
|
public SessionFactoryBuilder enableJpaListCompliance(boolean enabled) {
|
||||||
delegate.enableJpaListCompliance( enabled );
|
delegate.enableJpaListCompliance( enabled );
|
||||||
|
|
|
@ -62,6 +62,20 @@ public interface JpaComplianceSettings {
|
||||||
*/
|
*/
|
||||||
String JPA_QUERY_COMPLIANCE = "hibernate.jpa.compliance.query";
|
String JPA_QUERY_COMPLIANCE = "hibernate.jpa.compliance.query";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls whether Hibernate applies cascade
|
||||||
|
* {@link jakarta.persistence.CascadeType#PERSIST} or
|
||||||
|
* {@link org.hibernate.annotations.CascadeType#SAVE_UPDATE}
|
||||||
|
* at flush time. If enabled, Hibernate will cascade the standard
|
||||||
|
* JPA {@code PERSIST} operation. Otherwise, Hibernate will cascade
|
||||||
|
* the legacy {@code SAVE_UPDATE} operation.
|
||||||
|
*
|
||||||
|
* @settingDefault {@link #JPA_COMPLIANCE}
|
||||||
|
*
|
||||||
|
* @since 6.6
|
||||||
|
*/
|
||||||
|
String JPA_CASCADE_COMPLIANCE = "hibernate.jpa.compliance.cascade";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls whether Hibernate should treat what it would usually consider a
|
* Controls whether Hibernate should treat what it would usually consider a
|
||||||
* {@linkplain org.hibernate.collection.spi.PersistentBag "bag"}, that is, a
|
* {@linkplain org.hibernate.collection.spi.PersistentBag "bag"}, that is, a
|
||||||
|
|
|
@ -146,7 +146,7 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi
|
||||||
|
|
||||||
LOG.debug( "Processing flush-time cascades" );
|
LOG.debug( "Processing flush-time cascades" );
|
||||||
|
|
||||||
final PersistContext context = getContext();
|
final PersistContext context = getContext( session );
|
||||||
//safe from concurrent modification because of how concurrentEntries() is implemented on IdentityMap
|
//safe from concurrent modification because of how concurrentEntries() is implemented on IdentityMap
|
||||||
for ( Map.Entry<Object,EntityEntry> me : persistenceContext.reentrantSafeEntityEntries() ) {
|
for ( Map.Entry<Object,EntityEntry> me : persistenceContext.reentrantSafeEntityEntries() ) {
|
||||||
// for ( Map.Entry me : IdentityMap.concurrentEntries( persistenceContext.getEntityEntries() ) ) {
|
// for ( Map.Entry me : IdentityMap.concurrentEntries( persistenceContext.getEntityEntries() ) ) {
|
||||||
|
@ -169,19 +169,25 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi
|
||||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||||
persistenceContext.incrementCascadeLevel();
|
persistenceContext.incrementCascadeLevel();
|
||||||
try {
|
try {
|
||||||
Cascade.cascade( getCascadingAction(), CascadePoint.BEFORE_FLUSH, session, persister, object, anything );
|
Cascade.cascade( getCascadingAction(session), CascadePoint.BEFORE_FLUSH, session, persister, object, anything );
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
persistenceContext.decrementCascadeLevel();
|
persistenceContext.decrementCascadeLevel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PersistContext getContext() {
|
protected PersistContext getContext(EventSource session) {
|
||||||
return jpaBootstrap ? PersistContext.create() : null;
|
return jpaBootstrap || isJpaCascadeComplianceEnabled( session ) ? PersistContext.create() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CascadingAction<PersistContext> getCascadingAction() {
|
protected CascadingAction<PersistContext> getCascadingAction(EventSource session) {
|
||||||
return jpaBootstrap ? CascadingActions.PERSIST_ON_FLUSH : CascadingActions.SAVE_UPDATE;
|
return jpaBootstrap || isJpaCascadeComplianceEnabled( session )
|
||||||
|
? CascadingActions.PERSIST_ON_FLUSH
|
||||||
|
: CascadingActions.SAVE_UPDATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isJpaCascadeComplianceEnabled(EventSource session) {
|
||||||
|
return session.getSessionFactory().getSessionFactoryOptions().getJpaCompliance().isJpaCascadeComplianceEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -245,7 +245,7 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
|
||||||
mergedIntegrationSettings.putAll( integrationSettings );
|
mergedIntegrationSettings.putAll( integrationSettings );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the boot-strap service registry, which mainly handles class loader interactions
|
// Build the bootstrap service registry, which mainly handles classloader interactions
|
||||||
final BootstrapServiceRegistry bsr = buildBootstrapServiceRegistry(
|
final BootstrapServiceRegistry bsr = buildBootstrapServiceRegistry(
|
||||||
mergedIntegrationSettings != null ? mergedIntegrationSettings : integrationSettings,
|
mergedIntegrationSettings != null ? mergedIntegrationSettings : integrationSettings,
|
||||||
providedClassLoader,
|
providedClassLoader,
|
||||||
|
|
|
@ -21,6 +21,7 @@ public class JpaComplianceImpl implements JpaCompliance {
|
||||||
private final boolean closedCompliance;
|
private final boolean closedCompliance;
|
||||||
private final boolean cachingCompliance;
|
private final boolean cachingCompliance;
|
||||||
private final boolean loadByIdCompliance;
|
private final boolean loadByIdCompliance;
|
||||||
|
private final boolean cascadeCompliance;
|
||||||
|
|
||||||
public JpaComplianceImpl(
|
public JpaComplianceImpl(
|
||||||
boolean listCompliance,
|
boolean listCompliance,
|
||||||
|
@ -31,7 +32,8 @@ public class JpaComplianceImpl implements JpaCompliance {
|
||||||
boolean transactionCompliance,
|
boolean transactionCompliance,
|
||||||
boolean closedCompliance,
|
boolean closedCompliance,
|
||||||
boolean cachingCompliance,
|
boolean cachingCompliance,
|
||||||
boolean loadByIdCompliance) {
|
boolean loadByIdCompliance,
|
||||||
|
boolean cascadeCompliance) {
|
||||||
this.queryCompliance = queryCompliance;
|
this.queryCompliance = queryCompliance;
|
||||||
this.transactionCompliance = transactionCompliance;
|
this.transactionCompliance = transactionCompliance;
|
||||||
this.listCompliance = listCompliance;
|
this.listCompliance = listCompliance;
|
||||||
|
@ -41,6 +43,7 @@ public class JpaComplianceImpl implements JpaCompliance {
|
||||||
this.globalGeneratorNameScopeCompliance = globalGeneratorNameScopeCompliance;
|
this.globalGeneratorNameScopeCompliance = globalGeneratorNameScopeCompliance;
|
||||||
this.orderByMappingCompliance = orderByMappingCompliance;
|
this.orderByMappingCompliance = orderByMappingCompliance;
|
||||||
this.loadByIdCompliance = loadByIdCompliance;
|
this.loadByIdCompliance = loadByIdCompliance;
|
||||||
|
this.cascadeCompliance = cascadeCompliance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -53,6 +56,11 @@ public class JpaComplianceImpl implements JpaCompliance {
|
||||||
return transactionCompliance;
|
return transactionCompliance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isJpaCascadeComplianceEnabled() {
|
||||||
|
return cascadeCompliance;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isJpaListComplianceEnabled() {
|
public boolean isJpaListComplianceEnabled() {
|
||||||
return listCompliance;
|
return listCompliance;
|
||||||
|
@ -98,10 +106,16 @@ public class JpaComplianceImpl implements JpaCompliance {
|
||||||
private boolean transactionCompliance;
|
private boolean transactionCompliance;
|
||||||
private boolean closedCompliance;
|
private boolean closedCompliance;
|
||||||
private boolean loadByIdCompliance;
|
private boolean loadByIdCompliance;
|
||||||
|
private boolean cascadeCompliance;
|
||||||
|
|
||||||
public JpaComplianceBuilder() {
|
public JpaComplianceBuilder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JpaComplianceBuilder setCascadeCompliance(boolean cascadeCompliance) {
|
||||||
|
this.cascadeCompliance = cascadeCompliance;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public JpaComplianceBuilder setListCompliance(boolean listCompliance) {
|
public JpaComplianceBuilder setListCompliance(boolean listCompliance) {
|
||||||
this.listCompliance = listCompliance;
|
this.listCompliance = listCompliance;
|
||||||
return this;
|
return this;
|
||||||
|
@ -157,7 +171,8 @@ public class JpaComplianceImpl implements JpaCompliance {
|
||||||
transactionCompliance,
|
transactionCompliance,
|
||||||
closedCompliance,
|
closedCompliance,
|
||||||
cachingCompliance,
|
cachingCompliance,
|
||||||
loadByIdCompliance
|
loadByIdCompliance,
|
||||||
|
cascadeCompliance
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ public class MutableJpaComplianceImpl implements MutableJpaCompliance {
|
||||||
private boolean closedCompliance;
|
private boolean closedCompliance;
|
||||||
private boolean cachingCompliance;
|
private boolean cachingCompliance;
|
||||||
private boolean loadByIdCompliance;
|
private boolean loadByIdCompliance;
|
||||||
|
private boolean cascadeCompliance;
|
||||||
|
|
||||||
public MutableJpaComplianceImpl(Map<?,?> configurationSettings) {
|
public MutableJpaComplianceImpl(Map<?,?> configurationSettings) {
|
||||||
this(
|
this(
|
||||||
|
@ -38,6 +39,11 @@ public class MutableJpaComplianceImpl implements MutableJpaCompliance {
|
||||||
public MutableJpaComplianceImpl(Map<?,?> configurationSettings, boolean jpaByDefault) {
|
public MutableJpaComplianceImpl(Map<?,?> configurationSettings, boolean jpaByDefault) {
|
||||||
final Object legacyQueryCompliance = configurationSettings.get( AvailableSettings.JPAQL_STRICT_COMPLIANCE );
|
final Object legacyQueryCompliance = configurationSettings.get( AvailableSettings.JPAQL_STRICT_COMPLIANCE );
|
||||||
|
|
||||||
|
cascadeCompliance = ConfigurationHelper.getBoolean(
|
||||||
|
AvailableSettings.JPA_CASCADE_COMPLIANCE,
|
||||||
|
configurationSettings,
|
||||||
|
jpaByDefault
|
||||||
|
);
|
||||||
//noinspection deprecation
|
//noinspection deprecation
|
||||||
listCompliance = ConfigurationHelper.getBoolean(
|
listCompliance = ConfigurationHelper.getBoolean(
|
||||||
AvailableSettings.JPA_LIST_COMPLIANCE,
|
AvailableSettings.JPA_LIST_COMPLIANCE,
|
||||||
|
@ -96,6 +102,10 @@ public class MutableJpaComplianceImpl implements MutableJpaCompliance {
|
||||||
return transactionCompliance;
|
return transactionCompliance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isJpaCascadeComplianceEnabled() {
|
||||||
|
return cascadeCompliance;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isJpaListComplianceEnabled() {
|
public boolean isJpaListComplianceEnabled() {
|
||||||
return listCompliance;
|
return listCompliance;
|
||||||
|
@ -139,6 +149,11 @@ public class MutableJpaComplianceImpl implements MutableJpaCompliance {
|
||||||
this.listCompliance = listCompliance;
|
this.listCompliance = listCompliance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCascadeCompliance(boolean cascadeCompliance) {
|
||||||
|
this.cascadeCompliance = cascadeCompliance;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOrderByMappingCompliance(boolean orderByMappingCompliance) {
|
public void setOrderByMappingCompliance(boolean orderByMappingCompliance) {
|
||||||
this.orderByMappingCompliance = orderByMappingCompliance;
|
this.orderByMappingCompliance = orderByMappingCompliance;
|
||||||
|
@ -182,6 +197,7 @@ public class MutableJpaComplianceImpl implements MutableJpaCompliance {
|
||||||
public JpaCompliance immutableCopy() {
|
public JpaCompliance immutableCopy() {
|
||||||
JpaComplianceImpl.JpaComplianceBuilder builder = new JpaComplianceImpl.JpaComplianceBuilder();
|
JpaComplianceImpl.JpaComplianceBuilder builder = new JpaComplianceImpl.JpaComplianceBuilder();
|
||||||
builder = builder.setListCompliance( listCompliance )
|
builder = builder.setListCompliance( listCompliance )
|
||||||
|
.setCascadeCompliance( cascadeCompliance )
|
||||||
.setProxyCompliance( proxyCompliance )
|
.setProxyCompliance( proxyCompliance )
|
||||||
.setOrderByMappingCompliance( orderByMappingCompliance )
|
.setOrderByMappingCompliance( orderByMappingCompliance )
|
||||||
.setGlobalGeneratorNameCompliance( generatorNameScopeCompliance )
|
.setGlobalGeneratorNameCompliance( generatorNameScopeCompliance )
|
||||||
|
|
|
@ -80,6 +80,17 @@ public interface JpaCompliance {
|
||||||
*/
|
*/
|
||||||
boolean isJpaClosedComplianceEnabled();
|
boolean isJpaClosedComplianceEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JPA specifies that a {@link jakarta.persistence.CascadeType#PERSIST}
|
||||||
|
* operation should occur at flush time. The legacy behavior of Hibernate
|
||||||
|
* was a {@link org.hibernate.annotations.CascadeType#SAVE_UPDATE}.
|
||||||
|
*
|
||||||
|
* @return {@code true} indicates to behave in the spec-defined way
|
||||||
|
*
|
||||||
|
* @see org.hibernate.cfg.AvailableSettings#JPA_CASCADE_COMPLIANCE
|
||||||
|
*/
|
||||||
|
boolean isJpaCascadeComplianceEnabled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JPA spec says that an {@link jakarta.persistence.EntityNotFoundException}
|
* JPA spec says that an {@link jakarta.persistence.EntityNotFoundException}
|
||||||
* should be thrown when accessing an entity proxy which does not have
|
* should be thrown when accessing an entity proxy which does not have
|
||||||
|
|
|
@ -10,6 +10,8 @@ package org.hibernate.jpa.spi;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface MutableJpaCompliance extends JpaCompliance {
|
public interface MutableJpaCompliance extends JpaCompliance {
|
||||||
|
void setCascadeCompliance(boolean cascadeCompliance);
|
||||||
|
|
||||||
void setListCompliance(boolean listCompliance);
|
void setListCompliance(boolean listCompliance);
|
||||||
|
|
||||||
void setOrderByMappingCompliance(boolean orderByCompliance);
|
void setOrderByMappingCompliance(boolean orderByCompliance);
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package org.hibernate.orm.test.annotations.cascade.persist;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.CascadeType;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.Jpa;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
@Jpa(annotatedClasses =
|
||||||
|
{CascadePersistJpaTest.Parent.class,
|
||||||
|
CascadePersistJpaTest.Child.class},
|
||||||
|
jpaComplianceEnabled = true)
|
||||||
|
public class CascadePersistJpaTest {
|
||||||
|
@Test void test(EntityManagerFactoryScope scope) {
|
||||||
|
Parent p = new Parent();
|
||||||
|
scope.inTransaction(s -> s.persist(p));
|
||||||
|
scope.inTransaction(s -> {
|
||||||
|
Parent parent = s.find(Parent.class, p.id);
|
||||||
|
Child child = new Child();
|
||||||
|
child.parent = parent;
|
||||||
|
parent.children.add(child);
|
||||||
|
});
|
||||||
|
scope.inTransaction(s -> {
|
||||||
|
Parent parent = s.find(Parent.class, p.id);
|
||||||
|
assertEquals(1, parent.children.size());
|
||||||
|
Child child = parent.children.iterator().next();
|
||||||
|
s.remove(child);
|
||||||
|
parent.children.remove(child);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
static class Parent {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
Long id;
|
||||||
|
|
||||||
|
@OneToMany(cascade = CascadeType.PERSIST,
|
||||||
|
mappedBy = "parent")
|
||||||
|
Set<Child> children = new HashSet<>();
|
||||||
|
}
|
||||||
|
@Entity
|
||||||
|
static class Child {
|
||||||
|
@Id @GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Basic(optional = false)
|
||||||
|
String name = "child";
|
||||||
|
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
Parent parent;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package org.hibernate.orm.test.annotations.cascade.persist;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.CascadeType;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
import org.hibernate.cfg.JpaComplianceSettings;
|
||||||
|
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.Test;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
@SessionFactory
|
||||||
|
@DomainModel(annotatedClasses =
|
||||||
|
{CascadePersistSFTest.Parent.class,
|
||||||
|
CascadePersistSFTest.Child.class})
|
||||||
|
@ServiceRegistry(settings = @Setting(name=JpaComplianceSettings.JPA_CASCADE_COMPLIANCE,value="true"))
|
||||||
|
public class CascadePersistSFTest {
|
||||||
|
@Test void test(SessionFactoryScope scope) {
|
||||||
|
Parent p = new Parent();
|
||||||
|
scope.inTransaction(s -> s.persist(p));
|
||||||
|
scope.inTransaction(s -> {
|
||||||
|
Parent parent = s.find(Parent.class, p.id);
|
||||||
|
Child child = new Child();
|
||||||
|
child.parent = parent;
|
||||||
|
parent.children.add(child);
|
||||||
|
});
|
||||||
|
scope.inTransaction(s -> {
|
||||||
|
Parent parent = s.find(Parent.class, p.id);
|
||||||
|
assertEquals(1, parent.children.size());
|
||||||
|
Child child = parent.children.iterator().next();
|
||||||
|
s.remove(child);
|
||||||
|
parent.children.remove(child);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
static class Parent {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
Long id;
|
||||||
|
|
||||||
|
@OneToMany(cascade = CascadeType.PERSIST,
|
||||||
|
mappedBy = "parent")
|
||||||
|
Set<Child> children = new HashSet<>();
|
||||||
|
}
|
||||||
|
@Entity
|
||||||
|
static class Child {
|
||||||
|
@Id @GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Basic(optional = false)
|
||||||
|
String name = "child";
|
||||||
|
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
Parent parent;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,11 @@ public class JpaComplianceStub implements JpaCompliance {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isJpaCascadeComplianceEnabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isJpaListComplianceEnabled() {
|
public boolean isJpaListComplianceEnabled() {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.hibernate.event.internal.DefaultFlushEventListener;
|
||||||
import org.hibernate.event.internal.DefaultPersistEventListener;
|
import org.hibernate.event.internal.DefaultPersistEventListener;
|
||||||
import org.hibernate.event.service.spi.EventListenerRegistry;
|
import org.hibernate.event.service.spi.EventListenerRegistry;
|
||||||
import org.hibernate.event.spi.AutoFlushEventListener;
|
import org.hibernate.event.spi.AutoFlushEventListener;
|
||||||
|
import org.hibernate.event.spi.EventSource;
|
||||||
import org.hibernate.event.spi.EventType;
|
import org.hibernate.event.spi.EventType;
|
||||||
import org.hibernate.event.spi.FlushEntityEventListener;
|
import org.hibernate.event.spi.FlushEntityEventListener;
|
||||||
import org.hibernate.event.spi.FlushEventListener;
|
import org.hibernate.event.spi.FlushEventListener;
|
||||||
|
@ -142,12 +143,12 @@ public abstract class AbstractJPATest extends BaseSessionFactoryFunctionalTest {
|
||||||
public static final AutoFlushEventListener INSTANCE = new JPAAutoFlushEventListener();
|
public static final AutoFlushEventListener INSTANCE = new JPAAutoFlushEventListener();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CascadingAction<PersistContext> getCascadingAction() {
|
protected CascadingAction<PersistContext> getCascadingAction(EventSource session) {
|
||||||
return CascadingActions.PERSIST_ON_FLUSH;
|
return CascadingActions.PERSIST_ON_FLUSH;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PersistContext getContext() {
|
protected PersistContext getContext(EventSource session) {
|
||||||
return PersistContext.create();
|
return PersistContext.create();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,12 +158,12 @@ public abstract class AbstractJPATest extends BaseSessionFactoryFunctionalTest {
|
||||||
public static final FlushEventListener INSTANCE = new JPAFlushEventListener();
|
public static final FlushEventListener INSTANCE = new JPAFlushEventListener();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CascadingAction<PersistContext> getCascadingAction() {
|
protected CascadingAction<PersistContext> getCascadingAction(EventSource session) {
|
||||||
return CascadingActions.PERSIST_ON_FLUSH;
|
return CascadingActions.PERSIST_ON_FLUSH;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PersistContext getContext() {
|
protected PersistContext getContext(EventSource session) {
|
||||||
return PersistContext.create();
|
return PersistContext.create();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue