Fix PersistenceUnitUtilImpl#getIdentifier() throws NPE for NonAggregateIdentifier
This commit is contained in:
parent
eae9a39b14
commit
411355852a
|
@ -79,7 +79,7 @@ public class LazyAttributeLoadingInterceptor extends AbstractLazyLoadInterceptor
|
||||||
final EntityPersister persister = session.getFactory().getMetamodel().entityPersister( getEntityName() );
|
final EntityPersister persister = session.getFactory().getMetamodel().entityPersister( getEntityName() );
|
||||||
|
|
||||||
if ( isTemporarySession ) {
|
if ( isTemporarySession ) {
|
||||||
final Object id = persister.getIdentifier( target, null );
|
final Object id = persister.getIdentifier( target, session );
|
||||||
|
|
||||||
// Add an entry for this entity in the PC of the temp Session
|
// Add an entry for this entity in the PC of the temp Session
|
||||||
// NOTE : a few arguments that would be nice to pass along here...
|
// NOTE : a few arguments that would be nice to pass along here...
|
||||||
|
|
|
@ -51,7 +51,7 @@ public final class EntityPrinter {
|
||||||
result.put(
|
result.put(
|
||||||
entityPersister.getIdentifierPropertyName(),
|
entityPersister.getIdentifierPropertyName(),
|
||||||
entityPersister.getIdentifierType().toLoggableString(
|
entityPersister.getIdentifierType().toLoggableString(
|
||||||
entityPersister.getIdentifier( entity ),
|
entityPersister.getIdentifier( entity, factory ),
|
||||||
factory
|
factory
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -103,7 +103,7 @@ public class PersistenceUnitUtilImpl implements PersistenceUnitUtil, Serializabl
|
||||||
catch (MappingException ex) {
|
catch (MappingException ex) {
|
||||||
throw new IllegalArgumentException( entityClass.getName() + " is not an entity", ex );
|
throw new IllegalArgumentException( entityClass.getName() + " is not an entity", ex );
|
||||||
}
|
}
|
||||||
return persister.getIdentifier( entity, null );
|
return persister.getIdentifier( entity, persister.getFactory() );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.metamodel.mapping;
|
package org.hibernate.metamodel.mapping;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.IdentifierValue;
|
import org.hibernate.engine.spi.IdentifierValue;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,6 +31,10 @@ public interface EntityIdentifierMapping extends ValueMapping, ModelPart {
|
||||||
IdentifierValue getUnsavedStrategy();
|
IdentifierValue getUnsavedStrategy();
|
||||||
|
|
||||||
Object getIdentifier(Object entity, SharedSessionContractImplementor session);
|
Object getIdentifier(Object entity, SharedSessionContractImplementor session);
|
||||||
|
|
||||||
|
Object getIdentifier(Object entity, SessionFactoryImplementor sessionFactory);
|
||||||
|
|
||||||
void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session);
|
void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session);
|
||||||
|
|
||||||
Object instantiate();
|
Object instantiate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,6 +125,14 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
||||||
return propertyAccess.getGetter().get( entity );
|
return propertyAccess.getGetter().get( entity );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getIdentifier(Object entity, SessionFactoryImplementor sessionFactory) {
|
||||||
|
if ( entity instanceof HibernateProxy ) {
|
||||||
|
return ( (HibernateProxy) entity ).getHibernateLazyInitializer().getIdentifier();
|
||||||
|
}
|
||||||
|
return propertyAccess.getGetter().get( entity );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session) {
|
public void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session) {
|
||||||
propertyAccess.getSetter().set( entity, id, session.getFactory() );
|
propertyAccess.getSetter().set( entity, id, session.getFactory() );
|
||||||
|
|
|
@ -79,6 +79,15 @@ public class EmbeddedIdentifierMappingImpl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getIdentifier(Object entity, SharedSessionContractImplementor session) {
|
public Object getIdentifier(Object entity, SharedSessionContractImplementor session) {
|
||||||
|
return getIdentifier( entity );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getIdentifier(Object entity, SessionFactoryImplementor sessionFactory) {
|
||||||
|
return EmbeddedIdentifierMappingImpl.this.getIdentifier( entity );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getIdentifier(Object entity) {
|
||||||
if ( entity instanceof HibernateProxy ) {
|
if ( entity instanceof HibernateProxy ) {
|
||||||
return ( (HibernateProxy) entity ).getHibernateLazyInitializer().getIdentifier();
|
return ( (HibernateProxy) entity ).getHibernateLazyInitializer().getIdentifier();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.io.Serializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
import org.hibernate.EntityNameResolver;
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.PersistenceContext;
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
@ -24,12 +25,15 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
||||||
|
import org.hibernate.metamodel.spi.MetamodelImplementor;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
import org.hibernate.type.ComponentType;
|
import org.hibernate.type.ComponentType;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A "non-aggregated" composite identifier.
|
* A "non-aggregated" composite identifier.
|
||||||
|
@ -42,8 +46,8 @@ import org.hibernate.type.ComponentType;
|
||||||
public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentifierMapping {
|
public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentifierMapping {
|
||||||
|
|
||||||
private final List<SingularAttributeMapping> idAttributeMappings;
|
private final List<SingularAttributeMapping> idAttributeMappings;
|
||||||
private final ComponentType bootIdComponentType;
|
private final ComponentType mappedIdComponentType;
|
||||||
private final ComponentType bootCidComponentType;
|
private final ComponentType virtualComponentType;
|
||||||
|
|
||||||
private final boolean[] isBootIdPropertyManyToOne;
|
private final boolean[] isBootIdPropertyManyToOne;
|
||||||
|
|
||||||
|
@ -71,8 +75,8 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif
|
||||||
for ( int i = 0; i < propertySpan; i++ ) {
|
for ( int i = 0; i < propertySpan; i++ ) {
|
||||||
isBootIdPropertyManyToOne[i] = bootIdClassDescriptor.getProperty( i ).getValue() instanceof ManyToOne;
|
isBootIdPropertyManyToOne[i] = bootIdClassDescriptor.getProperty( i ).getValue() instanceof ManyToOne;
|
||||||
}
|
}
|
||||||
bootIdComponentType = (ComponentType) bootIdClassDescriptor.getType();
|
mappedIdComponentType = (ComponentType) bootIdClassDescriptor.getType();
|
||||||
bootCidComponentType = (ComponentType) bootCidDescriptor.getType();
|
virtualComponentType = (ComponentType) bootCidDescriptor.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -88,14 +92,75 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif
|
||||||
@Override
|
@Override
|
||||||
public Object getIdentifier(Object entity, SharedSessionContractImplementor session) {
|
public Object getIdentifier(Object entity, SharedSessionContractImplementor session) {
|
||||||
if ( hasContainingClass() ) {
|
if ( hasContainingClass() ) {
|
||||||
final Serializable disassemble = bootCidComponentType.disassemble( entity, session, null );
|
final Serializable disassemble = virtualComponentType.disassemble( entity, session, null );
|
||||||
return bootIdComponentType.assemble( disassemble, session, null );
|
return mappedIdComponentType.assemble( disassemble, session, null );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getIdentifier(Object entity, SessionFactoryImplementor sessionFactory){
|
||||||
|
if ( hasContainingClass() ) {
|
||||||
|
final Object id = mappedIdComponentType.instantiate();
|
||||||
|
final Object[] propertyValues = virtualComponentType.getPropertyValues( entity );
|
||||||
|
final Type[] subTypes = virtualComponentType.getSubtypes();
|
||||||
|
final Type[] copierSubTypes = mappedIdComponentType.getSubtypes();
|
||||||
|
final int length = subTypes.length;
|
||||||
|
for ( int i = 0; i < length; i++ ) {
|
||||||
|
//JPA 2 @MapsId + @IdClass points to the pk of the entity
|
||||||
|
if ( subTypes[i].isAssociationType() && !copierSubTypes[i].isAssociationType() ) {
|
||||||
|
propertyValues[i] = determineEntityId( propertyValues[i], sessionFactory );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mappedIdComponentType.setPropertyValues( id, propertyValues );
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object determineEntityId(Object entity, SessionFactoryImplementor sessionFactory) {
|
||||||
|
if ( entity == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( HibernateProxy.class.isInstance( entity ) ) {
|
||||||
|
// entity is a proxy, so we know it is not transient; just return ID from proxy
|
||||||
|
return ( (HibernateProxy) entity ).getHibernateLazyInitializer().getInternalIdentifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
final EntityPersister persister = resolveEntityPersister(
|
||||||
|
entity,
|
||||||
|
sessionFactory
|
||||||
|
);
|
||||||
|
|
||||||
|
return persister.getIdentifier( entity, sessionFactory );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EntityPersister resolveEntityPersister(Object entity, SessionFactoryImplementor sessionFactory) {
|
||||||
|
assert sessionFactory != null;
|
||||||
|
|
||||||
|
String entityName = null;
|
||||||
|
final MetamodelImplementor metamodel = sessionFactory.getMetamodel();
|
||||||
|
for ( EntityNameResolver entityNameResolver : metamodel.getEntityNameResolvers() ) {
|
||||||
|
entityName = entityNameResolver.resolveEntityName( entity );
|
||||||
|
if ( entityName != null ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( entityName == null ) {
|
||||||
|
// old fall-back
|
||||||
|
entityName = entity.getClass().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return metamodel.findEntityDescriptor( entityName );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object disassemble(Object value, SharedSessionContractImplementor session) {
|
public Object disassemble(Object value, SharedSessionContractImplementor session) {
|
||||||
if ( !getEmbeddableTypeDescriptor().getMappedJavaTypeDescriptor()
|
if ( !getEmbeddableTypeDescriptor().getMappedJavaTypeDescriptor()
|
||||||
|
@ -121,7 +186,7 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final SessionFactoryImplementor factory = session.getFactory();
|
final SessionFactoryImplementor factory = session.getFactory();
|
||||||
final Object[] propertyValues = bootIdComponentType.getPropertyValues( id, session );
|
final Object[] propertyValues = mappedIdComponentType.getPropertyValues( id, session );
|
||||||
forEachAttribute(
|
forEachAttribute(
|
||||||
(position, attribute) -> {
|
(position, attribute) -> {
|
||||||
Object propertyValue = propertyValues[position];
|
Object propertyValue = propertyValues[position];
|
||||||
|
@ -214,6 +279,6 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasContainingClass() {
|
public boolean hasContainingClass() {
|
||||||
return bootIdComponentType != bootCidComponentType;
|
return mappedIdComponentType != virtualComponentType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5029,7 +5029,7 @@ public abstract class AbstractEntityPersister
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getIdentifier(Object object) {
|
public Object getIdentifier(Object object) {
|
||||||
return getIdentifier( object, null );
|
return getIdentifier( object, getFactory() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -5037,6 +5037,11 @@ public abstract class AbstractEntityPersister
|
||||||
return identifierMapping.getIdentifier( entity, session );
|
return identifierMapping.getIdentifier( entity, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getIdentifier(Object entity, SessionFactoryImplementor sessionFactory){
|
||||||
|
return identifierMapping.getIdentifier( entity, sessionFactory );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session) {
|
public void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session) {
|
||||||
identifierMapping.setIdentifier( entity, id, session );
|
identifierMapping.setIdentifier( entity, id, session );
|
||||||
|
|
|
@ -821,6 +821,8 @@ public interface EntityPersister
|
||||||
*/
|
*/
|
||||||
Object getIdentifier(Object entity, SharedSessionContractImplementor session);
|
Object getIdentifier(Object entity, SharedSessionContractImplementor session);
|
||||||
|
|
||||||
|
Object getIdentifier(Object entity, SessionFactoryImplementor sessionFactoryImplementor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inject the identifier value into the given entity.
|
* Inject the identifier value into the given entity.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3395,8 +3395,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
associationKeyPart = identifierMapping;
|
associationKeyPart = identifierMapping;
|
||||||
associationKey = identifierMapping.getIdentifier(
|
associationKey = identifierMapping.getIdentifier(
|
||||||
literal.getLiteralValue(),
|
literal.getLiteralValue(),
|
||||||
null
|
getCreationContext().getSessionFactory());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if ( associationKeyPart instanceof BasicValuedMapping ) {
|
if ( associationKeyPart instanceof BasicValuedMapping ) {
|
||||||
return new QueryLiteral<>(
|
return new QueryLiteral<>(
|
||||||
|
|
|
@ -156,7 +156,7 @@ public class AnyType extends AbstractType implements CompositeType, AssociationT
|
||||||
final EntityPersister concretePersister = guessEntityPersister( entity );
|
final EntityPersister concretePersister = guessEntityPersister( entity );
|
||||||
return concretePersister == null
|
return concretePersister == null
|
||||||
? null
|
? null
|
||||||
: concretePersister.getIdentifier( entity, null );
|
: concretePersister.getIdentifier( entity,concretePersister.getFactory() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private EntityPersister guessEntityPersister(Object object) {
|
private EntityPersister guessEntityPersister(Object object) {
|
||||||
|
|
|
@ -324,7 +324,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
|
||||||
else {
|
else {
|
||||||
final Class mappedClass = persister.getMappedClass();
|
final Class mappedClass = persister.getMappedClass();
|
||||||
if ( mappedClass.isAssignableFrom( x.getClass() ) ) {
|
if ( mappedClass.isAssignableFrom( x.getClass() ) ) {
|
||||||
id = persister.getIdentifier( x );
|
id = persister.getIdentifier( x, factory );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
id = x;
|
id = x;
|
||||||
|
@ -353,7 +353,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( mappedClass.isAssignableFrom( x.getClass() ) ) {
|
if ( mappedClass.isAssignableFrom( x.getClass() ) ) {
|
||||||
xid = persister.getIdentifier( x );
|
xid = persister.getIdentifier( x, factory );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//JPA 2 case where @IdClass contains the id and not the associated entity
|
//JPA 2 case where @IdClass contains the id and not the associated entity
|
||||||
|
@ -368,7 +368,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( mappedClass.isAssignableFrom( y.getClass() ) ) {
|
if ( mappedClass.isAssignableFrom( y.getClass() ) ) {
|
||||||
yid = persister.getIdentifier( y );
|
yid = persister.getIdentifier( y, factory );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//JPA 2 case where @IdClass contains the id and not the associated entity
|
//JPA 2 case where @IdClass contains the id and not the associated entity
|
||||||
|
@ -504,7 +504,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
|
||||||
id = proxy.getHibernateLazyInitializer().getInternalIdentifier();
|
id = proxy.getHibernateLazyInitializer().getInternalIdentifier();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
id = persister.getIdentifier( value );
|
id = persister.getIdentifier( value, factory );
|
||||||
}
|
}
|
||||||
|
|
||||||
result.append( '#' )
|
result.append( '#' )
|
||||||
|
|
|
@ -0,0 +1,322 @@
|
||||||
|
/*
|
||||||
|
* 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.annotations.derivedidentities.bidirectional;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.internal.PersistenceUnitUtilImpl;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.CascadeType;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.IdClass;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
CompositeIdDerivedIdWithIdClassTest.ShoppingCart.class,
|
||||||
|
CompositeIdDerivedIdWithIdClassTest.LineItem.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
public class CompositeIdDerivedIdWithIdClassTest {
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void cleanup(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "delete from LineItem" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Cart" ).executeUpdate();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-11328")
|
||||||
|
public void testMergeTransientIdManyToOne(SessionFactoryScope scope) {
|
||||||
|
ShoppingCart transientCart = new ShoppingCart( "cart1" );
|
||||||
|
transientCart.addLineItem( new LineItem( 0, "description2", transientCart ) );
|
||||||
|
|
||||||
|
// assertion for HHH-11274 - checking for exception
|
||||||
|
final Object identifier = new PersistenceUnitUtilImpl( scope.getSessionFactory() ).getIdentifier( transientCart.getLineItems()
|
||||||
|
.get( 0 ) );
|
||||||
|
|
||||||
|
// merge ID with transient many-to-one
|
||||||
|
scope.inTransaction(
|
||||||
|
session ->
|
||||||
|
session.merge( transientCart )
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
ShoppingCart updatedCart = session.get( ShoppingCart.class, "cart1" );
|
||||||
|
// assertion for HHH-11274 - checking for exception
|
||||||
|
new PersistenceUnitUtilImpl( scope.getSessionFactory() )
|
||||||
|
.getIdentifier( transientCart.getLineItems().get( 0 ) );
|
||||||
|
|
||||||
|
assertEquals( 1, updatedCart.getLineItems().size() );
|
||||||
|
assertEquals( "description2", updatedCart.getLineItems().get( 0 ).getDescription() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-10623")
|
||||||
|
public void testMergeDetachedIdManyToOne(SessionFactoryScope scope) {
|
||||||
|
ShoppingCart cart = new ShoppingCart( "cart1" );
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session ->
|
||||||
|
session.persist( cart )
|
||||||
|
);
|
||||||
|
|
||||||
|
// cart is detached now
|
||||||
|
LineItem lineItem = new LineItem( 0, "description2", cart );
|
||||||
|
cart.addLineItem( lineItem );
|
||||||
|
|
||||||
|
// merge lineItem with an ID with detached many-to-one
|
||||||
|
scope.inTransaction(
|
||||||
|
session ->
|
||||||
|
session.merge( lineItem )
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
ShoppingCart updatedCart = session.get( ShoppingCart.class, "cart1" );
|
||||||
|
assertEquals( 1, updatedCart.getLineItems().size() );
|
||||||
|
assertEquals( "description2", updatedCart.getLineItems().get( 0 ).getDescription() );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-12007")
|
||||||
|
public void testBindTransientEntityWithTransientKeyManyToOne(SessionFactoryScope scope) {
|
||||||
|
|
||||||
|
ShoppingCart cart = new ShoppingCart( "cart" );
|
||||||
|
LineItem item = new LineItem( 0, "desc", cart );
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
String cartId = session.createQuery(
|
||||||
|
"select c.id from Cart c left join c.lineItems i where i = :item",
|
||||||
|
String.class
|
||||||
|
).setParameter( "item", item ).uniqueResult();
|
||||||
|
|
||||||
|
assertNull( cartId );
|
||||||
|
|
||||||
|
assertFalse( session.contains( item ) );
|
||||||
|
assertFalse( session.contains( cart ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-12007")
|
||||||
|
public void testBindTransientEntityWithPersistentKeyManyToOne(SessionFactoryScope scope) {
|
||||||
|
ShoppingCart cart = new ShoppingCart( "cart" );
|
||||||
|
LineItem item = new LineItem( 0, "desc", cart );
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.persist( cart );
|
||||||
|
String cartId = session.createQuery(
|
||||||
|
"select c.id from Cart c left join c.lineItems i where i = :item",
|
||||||
|
String.class
|
||||||
|
).setParameter( "item", item ).uniqueResult();
|
||||||
|
|
||||||
|
assertNull( cartId );
|
||||||
|
|
||||||
|
assertFalse( session.contains( item ) );
|
||||||
|
assertTrue( session.contains( cart ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-12007")
|
||||||
|
public void testBindTransientEntityWithDetachedKeyManyToOne(SessionFactoryScope scope) {
|
||||||
|
|
||||||
|
ShoppingCart cart = new ShoppingCart( "cart" );
|
||||||
|
LineItem item = new LineItem( 0, "desc", cart );
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
String cartId = session.createQuery(
|
||||||
|
"select c.id from Cart c left join c.lineItems i where i = :item",
|
||||||
|
String.class
|
||||||
|
).setParameter( "item", item ).uniqueResult();
|
||||||
|
|
||||||
|
assertNull( cartId );
|
||||||
|
|
||||||
|
assertFalse( session.contains( item ) );
|
||||||
|
assertFalse( session.contains( cart ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-12007")
|
||||||
|
public void testBindTransientEntityWithCopiedKeyManyToOne(SessionFactoryScope scope) {
|
||||||
|
|
||||||
|
ShoppingCart cart = new ShoppingCart( "cart" );
|
||||||
|
LineItem item = new LineItem( 0, "desc", new ShoppingCart( "cart" ) );
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
String cartId = session.createQuery(
|
||||||
|
"select c.id from Cart c left join c.lineItems i where i = :item",
|
||||||
|
String.class
|
||||||
|
).setParameter( "item", item ).uniqueResult();
|
||||||
|
|
||||||
|
assertNull( cartId );
|
||||||
|
|
||||||
|
assertFalse( session.contains( item ) );
|
||||||
|
assertFalse( session.contains( cart ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Cart")
|
||||||
|
public static class ShoppingCart implements Serializable {
|
||||||
|
@Id
|
||||||
|
@Column(name = "id", nullable = false)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "cart", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||||
|
private List<LineItem> lineItems = new ArrayList<>();
|
||||||
|
|
||||||
|
protected ShoppingCart() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShoppingCart(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<LineItem> getLineItems() {
|
||||||
|
return lineItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLineItem(LineItem lineItem) {
|
||||||
|
lineItems.add( lineItem );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if ( this == o ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( o == null || getClass() != o.getClass() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ShoppingCart that = (ShoppingCart) o;
|
||||||
|
return Objects.equals( id, that.id );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash( id );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "LineItem")
|
||||||
|
@IdClass(LineItem.Pk.class)
|
||||||
|
public static class LineItem implements Serializable {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "item_seq_number", nullable = false)
|
||||||
|
private Integer sequenceNumber;
|
||||||
|
|
||||||
|
@Column(name = "description")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "cart_id")
|
||||||
|
private ShoppingCart cart;
|
||||||
|
|
||||||
|
protected LineItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public LineItem(Integer sequenceNumber, String description, ShoppingCart cart) {
|
||||||
|
this.sequenceNumber = sequenceNumber;
|
||||||
|
this.description = description;
|
||||||
|
this.cart = cart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSequenceNumber() {
|
||||||
|
return sequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShoppingCart getCart() {
|
||||||
|
return cart;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if ( this == o ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( !( o instanceof LineItem ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LineItem lineItem = (LineItem) o;
|
||||||
|
return Objects.equals( getSequenceNumber(), lineItem.getSequenceNumber() ) &&
|
||||||
|
Objects.equals( getCart(), lineItem.getCart() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash( getSequenceNumber(), getCart() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Pk implements Serializable {
|
||||||
|
public Integer sequenceNumber;
|
||||||
|
public String cart;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if ( this == o ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( !( o instanceof Pk ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Pk pk = (Pk) o;
|
||||||
|
return Objects.equals( sequenceNumber, pk.sequenceNumber ) &&
|
||||||
|
Objects.equals( cart, pk.cart );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash( sequenceNumber, cart );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -570,6 +570,11 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getIdentifier(Object entity, SessionFactoryImplementor sessionFactoryImplementor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session) {
|
public void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -580,6 +580,11 @@ public class PersisterClassProviderTest {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getIdentifier(Object entity, SessionFactoryImplementor sessionFactoryImplementor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session) {
|
public void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,6 +212,11 @@ public class CustomPersister implements EntityPersister {
|
||||||
return ( (Custom) entity ).id;
|
return ( (Custom) entity ).id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getIdentifier(Object entity, SessionFactoryImplementor sessionFactoryImplementor) {
|
||||||
|
return ( (Custom) entity ).id;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session) {
|
public void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session) {
|
||||||
( (Custom) entity ).id = (String) id;
|
( (Custom) entity ).id = (String) id;
|
||||||
|
|
|
@ -1,329 +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.annotations.derivedidentities.bidirectional;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import jakarta.persistence.CascadeType;
|
|
||||||
import jakarta.persistence.Column;
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
import jakarta.persistence.IdClass;
|
|
||||||
import jakarta.persistence.JoinColumn;
|
|
||||||
import jakarta.persistence.ManyToOne;
|
|
||||||
import jakarta.persistence.OneToMany;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.jpa.internal.PersistenceUnitUtilImpl;
|
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
public class CompositeIdDerivedIdWithIdClassTest extends BaseCoreFunctionalTestCase {
|
|
||||||
@Override
|
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
|
||||||
return new Class<?>[] {
|
|
||||||
ShoppingCart.class,
|
|
||||||
LineItem.class
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void cleanup() {
|
|
||||||
Session s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
s.createQuery( "delete from LineItem" ).executeUpdate();
|
|
||||||
s.createQuery( "delete from Cart" ).executeUpdate();
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestForIssue(jiraKey = "HHH-11328")
|
|
||||||
public void testMergeTransientIdManyToOne() throws Exception {
|
|
||||||
ShoppingCart transientCart = new ShoppingCart( "cart1" );
|
|
||||||
transientCart.addLineItem( new LineItem( 0, "description2", transientCart ) );
|
|
||||||
|
|
||||||
// assertion for HHH-11274 - checking for exception
|
|
||||||
final Object identifier = new PersistenceUnitUtilImpl( sessionFactory() ).getIdentifier( transientCart.getLineItems().get( 0 ) );
|
|
||||||
|
|
||||||
// merge ID with transient many-to-one
|
|
||||||
Session s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
s.merge( transientCart );
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
ShoppingCart updatedCart = s.get( ShoppingCart.class, "cart1" );
|
|
||||||
// assertion for HHH-11274 - checking for exception
|
|
||||||
new PersistenceUnitUtilImpl( sessionFactory() ).getIdentifier( transientCart.getLineItems().get( 0 ) );
|
|
||||||
assertEquals( 1, updatedCart.getLineItems().size() );
|
|
||||||
assertEquals( "description2", updatedCart.getLineItems().get( 0 ).getDescription() );
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestForIssue(jiraKey = "HHH-10623")
|
|
||||||
public void testMergeDetachedIdManyToOne() throws Exception {
|
|
||||||
ShoppingCart cart = new ShoppingCart("cart1");
|
|
||||||
|
|
||||||
Session s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
s.persist( cart );
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
// cart is detached now
|
|
||||||
LineItem lineItem = new LineItem( 0, "description2", cart );
|
|
||||||
cart.addLineItem( lineItem );
|
|
||||||
|
|
||||||
// merge lineItem with an ID with detached many-to-one
|
|
||||||
s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
s.merge( lineItem );
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
ShoppingCart updatedCart = s.get( ShoppingCart.class, "cart1" );
|
|
||||||
assertEquals( 1, updatedCart.getLineItems().size() );
|
|
||||||
assertEquals("description2", updatedCart.getLineItems().get( 0 ).getDescription());
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestForIssue( jiraKey = "HHH-12007")
|
|
||||||
public void testBindTransientEntityWithTransientKeyManyToOne() {
|
|
||||||
|
|
||||||
ShoppingCart cart = new ShoppingCart( "cart" );
|
|
||||||
LineItem item = new LineItem( 0, "desc", cart );
|
|
||||||
|
|
||||||
Session s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
|
|
||||||
String cartId = s.createQuery(
|
|
||||||
"select c.id from Cart c left join c.lineItems i where i = :item",
|
|
||||||
String.class
|
|
||||||
).setParameter( "item", item ).uniqueResult();
|
|
||||||
|
|
||||||
assertNull( cartId );
|
|
||||||
|
|
||||||
assertFalse( s.contains( item ) );
|
|
||||||
assertFalse( s.contains( cart ) );
|
|
||||||
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestForIssue( jiraKey = "HHH-12007")
|
|
||||||
public void testBindTransientEntityWithPersistentKeyManyToOne() {
|
|
||||||
ShoppingCart cart = new ShoppingCart( "cart" );
|
|
||||||
LineItem item = new LineItem( 0, "desc", cart );
|
|
||||||
|
|
||||||
Session s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
|
|
||||||
session.persist( cart );
|
|
||||||
String cartId = s.createQuery(
|
|
||||||
"select c.id from Cart c left join c.lineItems i where i = :item",
|
|
||||||
String.class
|
|
||||||
).setParameter( "item", item ).uniqueResult();
|
|
||||||
|
|
||||||
assertNull( cartId );
|
|
||||||
|
|
||||||
assertFalse( s.contains( item ) );
|
|
||||||
assertTrue( s.contains( cart ) );
|
|
||||||
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestForIssue( jiraKey = "HHH-12007")
|
|
||||||
public void testBindTransientEntityWithDetachedKeyManyToOne() {
|
|
||||||
Session s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
|
|
||||||
ShoppingCart cart = new ShoppingCart( "cart" );
|
|
||||||
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
LineItem item = new LineItem( 0, "desc", cart );
|
|
||||||
|
|
||||||
s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
|
|
||||||
String cartId = s.createQuery(
|
|
||||||
"select c.id from Cart c left join c.lineItems i where i = :item",
|
|
||||||
String.class
|
|
||||||
).setParameter( "item", item ).uniqueResult();
|
|
||||||
|
|
||||||
assertNull( cartId );
|
|
||||||
|
|
||||||
assertFalse( s.contains( item ) );
|
|
||||||
assertFalse( s.contains( cart ) );
|
|
||||||
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestForIssue( jiraKey = "HHH-12007")
|
|
||||||
public void testBindTransientEntityWithCopiedKeyManyToOne() {
|
|
||||||
Session s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
|
|
||||||
ShoppingCart cart = new ShoppingCart( "cart" );
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
LineItem item = new LineItem( 0, "desc", new ShoppingCart( "cart" ) );
|
|
||||||
|
|
||||||
s = openSession();
|
|
||||||
s.getTransaction().begin();
|
|
||||||
|
|
||||||
String cartId = s.createQuery(
|
|
||||||
"select c.id from Cart c left join c.lineItems i where i = :item",
|
|
||||||
String.class
|
|
||||||
).setParameter( "item", item ).uniqueResult();
|
|
||||||
|
|
||||||
assertNull( cartId );
|
|
||||||
|
|
||||||
assertFalse( s.contains( item ) );
|
|
||||||
assertFalse( s.contains( cart ) );
|
|
||||||
|
|
||||||
s.getTransaction().commit();
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "Cart")
|
|
||||||
public static class ShoppingCart implements Serializable{
|
|
||||||
@Id
|
|
||||||
@Column(name = "id", nullable = false)
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
@OneToMany(mappedBy = "cart", cascade = CascadeType.ALL, orphanRemoval = true)
|
|
||||||
private List<LineItem> lineItems = new ArrayList<>();
|
|
||||||
|
|
||||||
protected ShoppingCart() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShoppingCart(String id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<LineItem> getLineItems() {
|
|
||||||
return lineItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addLineItem(LineItem lineItem) {
|
|
||||||
lineItems.add(lineItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
ShoppingCart that = (ShoppingCart) o;
|
|
||||||
return Objects.equals( id, that.id );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "LineItem")
|
|
||||||
@IdClass(LineItem.Pk.class)
|
|
||||||
public static class LineItem implements Serializable {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@Column(name = "item_seq_number", nullable = false)
|
|
||||||
private Integer sequenceNumber;
|
|
||||||
|
|
||||||
@Column(name = "description")
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@ManyToOne
|
|
||||||
@JoinColumn(name = "cart_id")
|
|
||||||
private ShoppingCart cart;
|
|
||||||
|
|
||||||
protected LineItem() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public LineItem(Integer sequenceNumber, String description, ShoppingCart cart) {
|
|
||||||
this.sequenceNumber = sequenceNumber;
|
|
||||||
this.description = description;
|
|
||||||
this.cart = cart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getSequenceNumber() {
|
|
||||||
return sequenceNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShoppingCart getCart() {
|
|
||||||
return cart;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (!(o instanceof LineItem)) return false;
|
|
||||||
LineItem lineItem = (LineItem) o;
|
|
||||||
return Objects.equals(getSequenceNumber(), lineItem.getSequenceNumber()) &&
|
|
||||||
Objects.equals(getCart(), lineItem.getCart());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash( getSequenceNumber(), getCart() );
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Pk implements Serializable {
|
|
||||||
public Integer sequenceNumber;
|
|
||||||
public String cart;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (!(o instanceof Pk)) return false;
|
|
||||||
Pk pk = (Pk) o;
|
|
||||||
return Objects.equals(sequenceNumber, pk.sequenceNumber) &&
|
|
||||||
Objects.equals(cart, pk.cart);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(sequenceNumber, cart);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue