Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2014 - 2023 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.impl;
import com.blazebit.persistence.BaseDeleteCriteriaBuilder;
import com.blazebit.persistence.JoinType;
import com.blazebit.persistence.ReturningBuilder;
import com.blazebit.persistence.ReturningObjectBuilder;
import com.blazebit.persistence.ReturningResult;
import com.blazebit.persistence.impl.function.colldml.CollectionDmlSupportFunction;
import com.blazebit.persistence.impl.query.CTENode;
import com.blazebit.persistence.impl.query.CollectionDeleteModificationQuerySpecification;
import com.blazebit.persistence.impl.query.CustomReturningSQLTypedQuery;
import com.blazebit.persistence.impl.query.CustomSQLQuery;
import com.blazebit.persistence.impl.query.EntityFunctionNode;
import com.blazebit.persistence.impl.query.QuerySpecification;
import com.blazebit.persistence.impl.util.SqlUtils;
import com.blazebit.persistence.parser.expression.ExpressionCopyContext;
import com.blazebit.persistence.parser.util.JpaMetamodelUtils;
import com.blazebit.persistence.spi.DbmsModificationState;
import com.blazebit.persistence.spi.DeleteJoinStyle;
import com.blazebit.persistence.spi.ExtendedAttribute;
import com.blazebit.persistence.spi.ExtendedManagedType;
import com.blazebit.persistence.spi.ExtendedQuerySupport;
import com.blazebit.persistence.spi.JoinTable;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
* @param The query result type
* @author Christian Beikov
* @since 1.2.0
*/
public abstract class AbstractDeleteCollectionCriteriaBuilder, Y> extends BaseDeleteCriteriaBuilderImpl {
protected final String collectionName;
protected final Type elementType;
protected final ExtendedAttribute collectionAttribute;
public AbstractDeleteCollectionCriteriaBuilder(MainQuery mainQuery, QueryContext queryContext, boolean isMainQuery, Class clazz, String alias, CTEManager.CTEKey cteKey, Class cteClass, Y result, CTEBuilderListener listener, String collectionName) {
super(mainQuery, queryContext, isMainQuery, clazz, alias, cteKey, cteClass, result, listener);
this.collectionName = collectionName;
ExtendedManagedType extendedManagedType = mainQuery.metamodel.getManagedType(ExtendedManagedType.class, entityType);
this.collectionAttribute = extendedManagedType.getAttribute(collectionName);
// Add the join here so that references in the where clause goes the the expected join node
// Also, this validates the collection actually exists
JoinNode join = joinManager.join(entityAlias + "." + collectionName, JoinManager.COLLECTION_DML_BASE_QUERY_ALIAS, JoinType.LEFT, false, true, null);
if (collectionAttribute.getJoinTable() != null) {
// We need to mark the driving table aliases specially to avoid replacing shadowed aliases of subqueries
// Since we use a separate select statement for query template generation, we introduce an SQL alias which we need to replace with the table name later
join.setDeReferenceFunction(mainQuery.jpaProvider.getCustomFunctionInvocation(CollectionDmlSupportFunction.FUNCTION_NAME, 1));
join.getParent().setDeReferenceFunction(mainQuery.jpaProvider.getCustomFunctionInvocation(CollectionDmlSupportFunction.FUNCTION_NAME, 1));
// In case we don't support joining in a delete statement, we need a way to reference the driving table in an exists subquery which we do by specially marking the correlation expressions
if (mainQuery.dbmsDialect.getDeleteJoinStyle() == DeleteJoinStyle.NONE || mainQuery.dbmsDialect.getDeleteJoinStyle() == DeleteJoinStyle.MERGE) {
join.setDisallowedDeReferenceAlias(aliasManager.generateRootAlias(join.getAlias()));
join.getParent().setDisallowedDeReferenceAlias(aliasManager.generateRootAlias(join.getParent().getAlias()));
}
// We need to track if "disallowed" attributes are de-referenced which requires a different rendering strategy because a join is needed
JoinTable joinTable = collectionAttribute.getJoinTable();
Set idAttributeNames = joinTable.getIdAttributeNames();
Set ownerAttributes = new HashSet<>(idAttributeNames.size());
for (String idAttributeName : idAttributeNames) {
ownerAttributes.add(idAttributeName);
int dotIdx = -1;
while ((dotIdx = idAttributeName.indexOf('.', dotIdx + 1)) != -1) {
ownerAttributes.add(idAttributeName.substring(0, dotIdx));
}
}
join.getParent().setAllowedDeReferences(ownerAttributes);
Set elementAttributes = new HashSet<>();
if (((PluralAttribute) collectionAttribute.getAttribute()).getElementType() instanceof ManagedType) {
String prefix = collectionAttribute.getAttributePathString() + ".";
for (Map.Entry> entry : extendedManagedType.getAttributes().entrySet()) {
if (entry.getKey().startsWith(prefix)) {
elementAttributes.add(entry.getKey().substring(prefix.length()));
}
}
}
join.setAllowedDeReferences(elementAttributes);
}
this.elementType = join.getType();
if (collectionAttribute.getJoinTable() == null && "".equals(collectionAttribute.getMappedBy())) {
throw new IllegalArgumentException("Cannot delete from the collection attribute '" + collectionName + "' of entity class '" + clazz.getName() + "' because it doesn't have a join table or a mapped by attribute!");
}
if (collectionAttribute.getMappedBy() != null) {
// Use a different alias to properly prefix paths with the collection role alias
JoinNode rootNode = joinManager.getRootNodeOrFail(null);
rootNode.getAliasInfo().setAlias(JoinManager.COLLECTION_DML_BASE_QUERY_ALIAS + "." + collectionAttribute.getMappedBy());
}
}
public AbstractDeleteCollectionCriteriaBuilder(AbstractDeleteCollectionCriteriaBuilder builder, MainQuery mainQuery, QueryContext queryContext, Map joinManagerMapping, ExpressionCopyContext copyContext) {
super(builder, mainQuery, queryContext, joinManagerMapping, copyContext);
this.collectionName = builder.collectionName;
this.collectionAttribute = builder.collectionAttribute;
this.elementType = builder.elementType;
}
@Override
protected void buildBaseQueryString(StringBuilder sbSelectFrom, boolean externalRepresentation, JoinNode lateralJoinNode, boolean countWrapped) {
JoinNode rootNode = joinManager.getRoots().get(0);
JoinTreeNode collectionTreeNode = rootNode.getNodes().get(collectionName);
boolean hasOtherJoinNodes = joinManager.getRoots().size() > 1
|| rootNode.getNodes().size() > 1
|| !rootNode.getTreatedJoinNodes().isEmpty()
|| !rootNode.getEntityJoinNodes().isEmpty()
|| collectionTreeNode.getJoinNodes().size() > 1
|| collectionTreeNode.getDefaultNode().hasChildNodes();
if (externalRepresentation) {
sbSelectFrom.append("DELETE FROM ");
sbSelectFrom.append(entityType.getName());
sbSelectFrom.append('(').append(collectionName).append(") ").append(entityAlias);
if (collectionAttribute.getJoinTable() == null) {
rootNode.getAliasInfo().setAlias(entityAlias);
}
rootNode.getNodes().get(collectionName).getDefaultNode().getAliasInfo().setAlias(entityAlias + "." + collectionName);
List whereClauseConjuncts = new ArrayList<>();
List optionalWhereClauseConjuncts = new ArrayList<>();
if (hasOtherJoinNodes) {
sbSelectFrom.append(" USING ");
joinManager.buildClause(sbSelectFrom, Collections.emptySet(), null, false, externalRepresentation, false, false, optionalWhereClauseConjuncts, whereClauseConjuncts, explicitVersionEntities, nodesToFetch, Collections.emptySet(), rootNode, false);
}
appendWhereClause(sbSelectFrom, externalRepresentation);
for (String whereClauseConjunct : whereClauseConjuncts) {
sbSelectFrom.append(" AND ").append(whereClauseConjunct);
}
if (collectionAttribute.getJoinTable() == null) {
rootNode.getAliasInfo().setAlias(JoinManager.COLLECTION_DML_BASE_QUERY_ALIAS + "." + collectionAttribute.getMappedBy());
}
rootNode.getNodes().get(collectionName).getDefaultNode().getAliasInfo().setAlias(JoinManager.COLLECTION_DML_BASE_QUERY_ALIAS);
} else if (collectionAttribute.getJoinTable() == null) {
sbSelectFrom.append("DELETE FROM ");
sbSelectFrom.append(((EntityType) elementType).getName());
sbSelectFrom.append(' ');
sbSelectFrom.append(JoinManager.COLLECTION_DML_BASE_QUERY_ALIAS);
appendWhereClause(sbSelectFrom, externalRepresentation);
} else {
// The internal representation is just a "hull" to hold the parameters at the appropriate positions
sbSelectFrom.append("SELECT 1");
StringBuilder tempSb = new StringBuilder();
// During rendering we discover if the a disallowed de-reference is used, so we render this in to a temporary string builder
appendWhereClause(tempSb, externalRepresentation);
if (hasOtherJoinNodes || rootNode.isDisallowedDeReferenceUsed() || collectionTreeNode.getDefaultNode().isDisallowedDeReferenceUsed()) {
if (mainQuery.dbmsDialect.getDeleteJoinStyle() == DeleteJoinStyle.NONE || mainQuery.dbmsDialect.getDeleteJoinStyle() == DeleteJoinStyle.MERGE) {
sbSelectFrom.append(" FROM ");
sbSelectFrom.append(entityType.getName());
sbSelectFrom.append(' ');
sbSelectFrom.append(entityAlias);
sbSelectFrom.append(" LEFT JOIN ");
sbSelectFrom.append(entityAlias).append('.').append(collectionName)
.append(' ').append(JoinManager.COLLECTION_DML_BASE_QUERY_ALIAS);
sbSelectFrom.append(" WHERE EXISTS (SELECT 1");
List whereClauseConjuncts = new ArrayList<>();
List optionalWhereClauseConjuncts = new ArrayList<>();
joinManager.buildClause(sbSelectFrom, Collections.emptySet(), null, false, externalRepresentation, false, false, optionalWhereClauseConjuncts, whereClauseConjuncts, explicitVersionEntities, nodesToFetch, Collections.emptySet(), rootNode, true);
sbSelectFrom.append(tempSb);
for (String whereClauseConjunct : whereClauseConjuncts) {
sbSelectFrom.append(" AND ").append(whereClauseConjunct);
}
sbSelectFrom.append(')');
} else {
List whereClauseConjuncts = new ArrayList<>();
List optionalWhereClauseConjuncts = new ArrayList<>();
joinManager.buildClause(sbSelectFrom, Collections.emptySet(), null, false, externalRepresentation, false, false, optionalWhereClauseConjuncts, whereClauseConjuncts, explicitVersionEntities, nodesToFetch, Collections.emptySet(), rootNode, true);
appendWhereClause(sbSelectFrom, whereClauseConjuncts, optionalWhereClauseConjuncts, lateralJoinNode);
}
} else {
List whereClauseConjuncts = new ArrayList<>();
List optionalWhereClauseConjuncts = new ArrayList<>();
joinManager.buildClause(sbSelectFrom, Collections.emptySet(), null, false, externalRepresentation, false, false, optionalWhereClauseConjuncts, whereClauseConjuncts, explicitVersionEntities, nodesToFetch, Collections.emptySet(), null, true);
sbSelectFrom.append(tempSb);
for (String whereClauseConjunct : whereClauseConjuncts) {
sbSelectFrom.append(" AND ").append(whereClauseConjunct);
}
}
}
}
@Override
protected Query getQuery(Map includedModificationStates) {
if (collectionAttribute.getJoinTable() == null) {
return super.getQuery(includedModificationStates);
} else {
Query baseQuery = em.createQuery(getBaseQueryStringWithCheck(null, null));
QuerySpecification querySpecification = getQuerySpecification(baseQuery, getCountExampleQuery(), getReturningColumns(), null, includedModificationStates);
CustomSQLQuery query = new CustomSQLQuery(
querySpecification,
baseQuery,
parameterManager.getCriteriaNameMapping(),
parameterManager.getTransformers(),
parameterManager.getValuesParameters(),
parameterManager.getValuesBinders()
);
parameterManager.parameterizeQuery(query);
return query;
}
}
@Override
protected TypedQuery> getExecuteWithReturningQuery(TypedQuery