Removed unnecessary visitedNavigablePath from LoaderSelectBuilder and added bidirectionalPropertyName for circularity detection

This commit is contained in:
Andrea Boriero 2020-06-25 15:28:25 +01:00
parent 6aefe00c1e
commit 3c7a208b96
8 changed files with 87 additions and 30 deletions

View File

@ -834,6 +834,17 @@ public static String nullIfEmpty(String value) {
return isEmpty( value ) ? null : value;
}
public static String subStringNullIfEmpty(String value, Character startChar) {
if ( isEmpty( value ) ) {
return null;
}
int index = value.indexOf( startChar );
if ( index != -1 ) {
return value.substring( index + 1 );
}
return value;
}
public static List<String> parseCommaSeparatedString(String incomingString) {
return CommaSeparatedStringHelper.parseCommaSeparatedString( incomingString );
}

View File

@ -82,8 +82,6 @@
public class LoaderSelectBuilder {
private static final Logger log = Logger.getLogger( LoaderSelectBuilder.class );
private HashMap<String, List<Fetch>> visitedNavigablePath = new HashMap<>();
/**
* Create an SQL AST select-statement based on matching one-or-more keys
*
@ -435,10 +433,6 @@ private List<Fetch> visitFetches(FetchParent fetchParent, QuerySpec querySpec, L
final List<Fetch> fetches = new ArrayList<>();
String fullPath = fetchParent.getNavigablePath().getFullPath();
final List<Fetch> fullPathFetches = visitedNavigablePath.get( fullPath );
if ( fullPathFetches != null ) {
return fullPathFetches;
}
final BiConsumer<Fetchable, Boolean> processor = createFetchableBiConsumer( fetchParent, querySpec, creationState, fetches );
@ -449,7 +443,6 @@ private List<Fetch> visitFetches(FetchParent fetchParent, QuerySpec querySpec, L
}
referencedMappingContainer.visitFetchables(
fetchable -> processor.accept( fetchable, false ), null );
visitedNavigablePath.put( fullPath, fetches );
return fetches;
}
@ -459,11 +452,11 @@ private BiConsumer<Fetchable, Boolean> createFetchableBiConsumer(
LoaderSqlAstCreationState creationState,
List<Fetch> fetches) {
return (fetchable, isKeyFetchable) -> {
NavigablePath navigablePath = fetchParent.getNavigablePath();
NavigablePath panrentNavigablePath = fetchParent.getNavigablePath();
if ( isKeyFetchable ) {
navigablePath = navigablePath.append( EntityIdentifierMapping.ROLE_LOCAL_NAME );
panrentNavigablePath = panrentNavigablePath.append( EntityIdentifierMapping.ROLE_LOCAL_NAME );
}
final NavigablePath fetchablePath = navigablePath.append( fetchable.getFetchableName() );
final NavigablePath fetchablePath = panrentNavigablePath.append( fetchable.getFetchableName() );
final Fetch biDirectionalFetch = fetchable.resolveCircularFetch(
fetchablePath,

View File

@ -56,5 +56,5 @@ default void visitFetchables(Consumer<Fetchable> fetchableConsumer, EntityMappin
String getSeparateCollectionTable();
String getMappedBy();
String getBidirectionalPropertyName();
}

View File

@ -18,11 +18,11 @@
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.jpa.spi.JpaCompliance;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.IndexedCollection;
import org.hibernate.mapping.List;
import org.hibernate.mapping.OneToOne;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
@ -98,7 +98,7 @@ public interface Aware {
private final FetchStyle fetchStyle;
private final CascadeStyle cascadeStyle;
private final String mappedBy;
private final String bidirectionalPropertyName;
private final CollectionPersister collectionDescriptor;
private final String separateCollectionTable;
@ -174,7 +174,8 @@ public PluralAttributeMappingImpl(
this.fetchStyle = fetchStyle;
this.cascadeStyle = cascadeStyle;
this.collectionDescriptor = collectionDescriptor;
this.mappedBy = bootDescriptor.getMappedByProperty();
this.bidirectionalPropertyName = StringHelper.subStringNullIfEmpty( bootDescriptor.getMappedByProperty(), '.');
this.sqlAliasStem = SqlAliasStemHelper.INSTANCE.generateStemFromAttributeName( attributeName );
@ -393,8 +394,8 @@ public String getSeparateCollectionTable() {
}
@Override
public String getMappedBy() {
return mappedBy;
public String getBidirectionalPropertyName() {
return bidirectionalPropertyName;
}
@Override

View File

@ -76,7 +76,7 @@ public enum Cardinality {
private final boolean referringPrimaryKey;
private final Cardinality cardinality;
private String mappedBy;
private String bidirectionalPropertyName;
private ForeignKeyDescriptor foreignKeyDescriptor;
private ForeignKeyDirection foreignKeyDirection;
@ -126,12 +126,61 @@ public ToOneAttributeMapping(
else {
assert bootValue instanceof OneToOne;
cardinality = Cardinality.ONE_TO_ONE;
String mappedByProperty = ( (OneToOne) bootValue ).getMappedByProperty();
/*
The otherSidePropertyName value is used to determine bidirectionality based on the navigablePath string
e.g.
class Card{
@OneToMany( mappedBy = "card")
Set<CardField> fields;
}
class CardField{
@ManyToOne(optional = false)
Card card;
@ManyToOne(optional = false)
Card card1;
}
NavigablePath(CardField.card.fields) fields is consideredBidirectional
NavigablePath(CardField.card1.fields) fields is NOT bidirectional
e.g. Embeddable case
class Card{
@OneToMany( mappedBy = "primaryKey.card")
Set<CardField> fields;
}
class CardField{
@EmbeddedId
PrimaryKey primaryKey;
}
@Embeddable
class PrimaryKey implements Serializable {
@ManyToOne(optional = false)
Card card;
}
in such case the mappedBy is "primaryKey.card"
the the navigable path is NavigablePath(Card.fields.{element}.{id}.card) and it does not contain the "primaryKey" part
so in ored to recognize the bidirectionality the "primaryKey." is removed from the otherSidePropertyName value.
*/
String mappedByProperty = StringHelper.subStringNullIfEmpty(
( (OneToOne) bootValue ).getMappedByProperty(),
'.'
);
if ( mappedByProperty == null ) {
mappedBy = StringHelper.nullIfEmpty( referencedPropertyName );
bidirectionalPropertyName = StringHelper.subStringNullIfEmpty( referencedPropertyName, '.' );
}
else {
mappedBy = mappedByProperty;
bidirectionalPropertyName = mappedByProperty;
}
}
@ -193,7 +242,7 @@ public Fetch resolveCircularFetch(
modelPart = creationState.resolveModelPart( parent );
}
if ( this.mappedBy != null && parent.getFullPath().endsWith( this.mappedBy ) ) {
if ( this.bidirectionalPropertyName != null && parent.getFullPath().endsWith( this.bidirectionalPropertyName ) ) {
/*
class Child {
@OneToOne(mappedBy = "biologicalChild")
@ -220,7 +269,7 @@ class Mother {
/*
check if mappedBy is on the other side of the association
*/
final String otherSideMappedBy = getOtherSideMappedBy( modelPart, parent.getParent(), creationState );
final String otherSideMappedBy = getOthrerSideMappedBy( modelPart, parent.getParent(), creationState );
if ( otherSideMappedBy != null ) {
/*
class Child {
@ -280,26 +329,30 @@ class Mother {
return null;
}
private String getOtherSideMappedBy(
private String getOthrerSideMappedBy(
ModelPart modelPart,
NavigablePath parentOfParent,
DomainResultCreationState creationState) {
if ( modelPart instanceof ToOneAttributeMapping ) {
return ( (ToOneAttributeMapping) modelPart ).getMappedBy();
return ( (ToOneAttributeMapping) modelPart ).getBidirectionalPropertyName();
}
if ( modelPart instanceof PluralAttributeMapping ) {
return ( (PluralAttributeMapping) modelPart ).getBidirectionalPropertyName();
}
if ( modelPart instanceof EntityCollectionPart ) {
if ( parentOfParent.getFullPath().endsWith( EntityIdentifierMapping.ROLE_LOCAL_NAME ) ) {
parentOfParent = parentOfParent.getParent();
}
return ( (PluralAttributeMapping) creationState.resolveModelPart( parentOfParent ) ).getMappedBy();
return ( (PluralAttributeMapping) creationState.resolveModelPart( parentOfParent ) ).getBidirectionalPropertyName();
}
return null;
}
public String getMappedBy(){
return mappedBy;
public String getBidirectionalPropertyName(){
return bidirectionalPropertyName;
}
private Fetch createCircularBiDirectionalFetch(

View File

@ -82,7 +82,7 @@ public AbstractEntityResultGraphNode(
}
}
else {
identifierResult = entityDescriptor.getIdentifierMapping().createDomainResult(
identifierResult = identifierMapping.createDomainResult(
navigablePath.append( EntityIdentifierMapping.ROLE_LOCAL_NAME ),
entityTableGroup,
null,

View File

@ -43,7 +43,7 @@ public void initializeInstance(RowProcessingState rowProcessingState) {
return;
}
final String entityName = concreteDescriptor.getEntityName();
String uniqueKeyPropertyName = fetchedAttribute.getMappedBy();
String uniqueKeyPropertyName = fetchedAttribute.getBidirectionalPropertyName();
final SharedSessionContractImplementor session = rowProcessingState.getSession();

View File

@ -200,7 +200,6 @@ public Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourcePr
if ( initializer.getInitializedInstance() == null ) {
initializer.resolveKey( rowProcessingState );
initializer.resolveInstance( rowProcessingState );
initializer.initializeInstance( rowProcessingState );
}
return initializer.getInitializedInstance();
}