Skip to content

Commit

Permalink
Fixed #198 - Added detection of the join column source to be able to …
Browse files Browse the repository at this point in the history
…determine if single valued association ids should be rendered
  • Loading branch information
beikov committed Mar 16, 2017
1 parent d8fed89 commit 3e12fa1
Show file tree
Hide file tree
Showing 27 changed files with 593 additions and 118 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.blazebit.persistence.spi;

import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.ManagedType;

/**
* A JPA provider implementation provides information about which features are supported by a JPA implementation.
Expand Down Expand Up @@ -188,6 +189,15 @@ public interface JpaProvider {
*/
public boolean supportsCountStar();

/**
* Whether the join columns for the given attribute are in a foreign table.
*
* @param ownerClass The owner of the attribute
* @param attributeName The attribute name to check
* @return True if join columns are in a foreign table, false otherwise
*/
public boolean isForeignJoinColumn(ManagedType<?> ownerClass, String attributeName);

/**
* Whether the given attribute is a collection that uses a join table.
*
Expand All @@ -211,7 +221,7 @@ public interface JpaProvider {
*
* without generating an extra join.
*
* @return true if supported, else fales
* @return true if supported, else false
*/
public boolean supportsSingleValuedAssociationIdExpressions();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
Expand Down Expand Up @@ -51,10 +50,6 @@ public class EntitySelectResolveVisitor extends VisitorAdapter {
private final EntityMetamodel m;
private final Set<PathExpression> pathExpressions;

public EntitySelectResolveVisitor(EntityMetamodel m) {
this(m, new LinkedHashSet<PathExpression>());
}

public EntitySelectResolveVisitor(EntityMetamodel m, Set<PathExpression> pathExpressions) {
this.m = m;
this.pathExpressions = pathExpressions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@

import javax.persistence.Query;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EmbeddableType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.IdentifiableType;
import javax.persistence.metamodel.ListAttribute;
Expand Down Expand Up @@ -1664,10 +1665,27 @@ private boolean isSingleValuedAssociationId(JoinResult joinResult, List<PathElem
// A naked root treat like TREAT(alias AS Subtype) has no attribute
return false;
}

if (maybeSingularAssociation.getPersistentAttributeType() != Attribute.PersistentAttributeType.MANY_TO_ONE
// TODO: to be able to support ONE_TO_ONE we need to know where the FK is
// && maybeSingularAssociation.getPersistentAttributeType() != Attribute.PersistentAttributeType.ONE_TO_ONE
&& maybeSingularAssociation.getPersistentAttributeType() != Attribute.PersistentAttributeType.ONE_TO_ONE
) {
// Attributes that are not ManyToOne or OneToOne can't possibly be single value association sources
return false;
}

if (maybeSingularAssociation instanceof MapKeyAttribute<?, ?>) {
// Skip the foreign join column check for map keys
// They aren't allowed as join sources in the JPA providers yet so we can only render them directly
} else if (baseType instanceof EmbeddableType<?>) {
// Get the base type. This is important if the path is "deeper" i.e. when having embeddables
baseType = JpaUtils.getManagedType(metamodel, parent.getPropertyClass(), parentTypeName);
String attributePath = joinResult.joinFields(maybeSingularAssociationName);
if (mainQuery.jpaProvider.isForeignJoinColumn(baseType, attributePath)) {
// If the attribute is part of
return false;
}
} else if (mainQuery.jpaProvider.isForeignJoinColumn(baseType, maybeSingularAssociation.getName())) {
// If the attribute is part of
return false;
}

Expand Down Expand Up @@ -2241,7 +2259,7 @@ private boolean hasField() {

private String joinFields(String field) {
if (fields == null || fields.isEmpty()) {
return null;
return field;
}

StringBuilder sb = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ public ReturningResult<T> getSingleResult() {
Query baseQuery = participatingQueries.get(0);
baseQuery.setFirstResult(firstResult);
baseQuery.setMaxResults(maxResults);
// TODO: hibernate will return the object directly for single attribute case instead of an object array

ReturningResult<Object[]> result = extendedQuerySupport.executeReturning(serviceProvider, participatingQueries, delegate, sql);
List<Object[]> resultList = result.getResultList();
final int updateCount = result.getUpdateCount();
if (requiresWrapping) {
// NOTE: Hibernate will return the object directly for single attribute case instead of an object array
int size = resultList.size();
List<Object[]> newResultList = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,6 @@

package com.blazebit.persistence.testsuite.entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Basic;
import javax.persistence.Embedded;
import javax.persistence.Entity;
Expand All @@ -40,6 +28,17 @@
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2014 - 2017 Blazebit.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.blazebit.persistence.testsuite.entity;

import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.OneToOne;
import java.io.Serializable;

/**
*
* @author Christian Beikov
* @since 1.2.0
*/
@Entity
public class DocumentForOneToOne extends Ownable implements Serializable {
private static final long serialVersionUID = 1L;

private String name;
private DocumentInfo documentInfo;
private DocumentInfo documentInfo2;

@Basic(optional = false)
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@OneToOne(mappedBy = "document")
public DocumentInfo getDocumentInfo() {
return documentInfo;
}

public void setDocumentInfo(DocumentInfo documentInfo) {
this.documentInfo = documentInfo;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2014 - 2017 Blazebit.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.blazebit.persistence.testsuite.entity;

import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToOne;
import java.io.Serializable;

/**
*
* @author Christian Beikov
* @since 1.2.0
*/
@Entity
public class DocumentForOneToOneJoinTable extends Ownable implements Serializable {
private static final long serialVersionUID = 1L;

private String name;
private DocumentInfo documentInfoJoinTable;

@Basic(optional = false)
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@OneToOne
@JoinTable(
name = "document_extra",
joinColumns = @JoinColumn(name = "document_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "document_info_id", referencedColumnName = "id")
)
public DocumentInfo getDocumentInfoJoinTable() {
return documentInfoJoinTable;
}

public void setDocumentInfoJoinTable(DocumentInfo documentInfoJoinTable) {
this.documentInfoJoinTable = documentInfoJoinTable;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2014 - 2017 Blazebit.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.blazebit.persistence.testsuite.entity;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import java.io.Serializable;

/**
*
* @author Christian Beikov
* @since 1.2.0
*/
@Entity
public class DocumentInfo implements Serializable {
private static final long serialVersionUID = 1L;

private Long id;
private DocumentForOneToOne document;
private String someInfo;

@Id
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

@OneToOne
@JoinColumn(name = "document_id")
public DocumentForOneToOne getDocument() {
return document;
}

public void setDocument(DocumentForOneToOne document) {
this.document = document;
}

public String getSomeInfo() {
return someInfo;
}

public void setSomeInfo(String someInfo) {
this.someInfo = someInfo;
}
}
3 changes: 3 additions & 0 deletions core/testsuite/src/main/resources/META-INF/persistence.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
<class>com.blazebit.persistence.testsuite.entity.DeletePersonCTE</class>
<class>com.blazebit.persistence.testsuite.entity.Document</class>
<class>com.blazebit.persistence.testsuite.entity.DocumentForEntityKeyMaps</class>
<class>com.blazebit.persistence.testsuite.entity.DocumentForOneToOneJoinTable</class>
<class>com.blazebit.persistence.testsuite.entity.DocumentForOneToOne</class>
<class>com.blazebit.persistence.testsuite.entity.DocumentInfo</class>
<class>com.blazebit.persistence.testsuite.entity.DocumentNodeCTE</class>
<class>com.blazebit.persistence.testsuite.entity.DocumentTupleEntity</class>
<class>com.blazebit.persistence.testsuite.entity.EmbeddableTestEntity</class>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import java.util.TreeSet;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import com.blazebit.persistence.ReturningObjectBuilder;
import com.blazebit.persistence.SimpleReturningBuilder;
Expand All @@ -50,9 +49,7 @@
import com.blazebit.persistence.testsuite.base.category.NoMSSQL;
import com.blazebit.persistence.testsuite.entity.Document;
import com.blazebit.persistence.testsuite.entity.IdHolderCTE;
import com.blazebit.persistence.testsuite.entity.IntIdEntity;
import com.blazebit.persistence.testsuite.entity.Person;
import com.blazebit.persistence.testsuite.entity.Version;
import com.blazebit.persistence.testsuite.tx.TxVoidWork;

/**
Expand All @@ -68,13 +65,9 @@ public class DeleteTest extends AbstractCoreTest {

@Override
protected Class<?>[] getEntityClasses() {
return new Class<?>[] {
Document.class,
Version.class,
IntIdEntity.class,
Person.class,
return concat(super.getEntityClasses(), new Class<?>[] {
IdHolderCTE.class
};
});
}

@Before
Expand Down
Loading

0 comments on commit 3e12fa1

Please sign in to comment.