
com.blazebit.persistence.impl.AbstractModificationCriteriaBuilder Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2015 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 java.util.*;
import javax.persistence.Query;
import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import com.blazebit.persistence.BaseModificationCriteriaBuilder;
import com.blazebit.persistence.CommonQueryBuilder;
import com.blazebit.persistence.FullSelectCTECriteriaBuilder;
import com.blazebit.persistence.ReturningBuilder;
import com.blazebit.persistence.ReturningModificationCriteriaBuilderFactory;
import com.blazebit.persistence.ReturningObjectBuilder;
import com.blazebit.persistence.ReturningResult;
import com.blazebit.persistence.SelectRecursiveCTECriteriaBuilder;
import com.blazebit.persistence.impl.builder.object.ReturningTupleObjectBuilder;
import com.blazebit.persistence.impl.dialect.DB2DbmsDialect;
import com.blazebit.persistence.impl.query.*;
import com.blazebit.persistence.spi.DbmsModificationState;
import com.blazebit.persistence.spi.DbmsStatementType;
/**
*
* @param The entity type of this modification builder
* @author Christian Beikov
* @since 1.1.0
*/
public abstract class AbstractModificationCriteriaBuilder, Y> extends AbstractCommonQueryBuilder, AbstractCommonQueryBuilder, ?, ?, ?, ?>, BaseFinalSetOperationBuilderImpl> implements BaseModificationCriteriaBuilder, CTEInfoBuilder {
protected final EntityType entityType;
protected final String entityAlias;
protected final EntityType> cteType;
protected final String cteName;
protected final Y result;
protected final CTEBuilderListener listener;
protected final boolean isReturningEntityAliasAllowed;
protected final Map returningAttributeBindingMap;
@SuppressWarnings("unchecked")
public AbstractModificationCriteriaBuilder(MainQuery mainQuery, boolean isMainQuery, DbmsStatementType statementType, Class clazz, String alias, String cteName, Class> cteClass, Y result, CTEBuilderListener listener) {
// NOTE: using tuple here because this class is used for the join manager and tuple is definitively not an entity
// but in case of the insert criteria, the appropriate return type which is convenient because update and delete don't have a return type
super(mainQuery, isMainQuery, statementType, (Class) Tuple.class, null);
// set defaults
if (alias == null) {
alias = clazz.getSimpleName().toLowerCase();
} else {
// If the user supplies an alias, the intention is clear
fromClassExplicitelySet = true;
}
this.entityType = em.getMetamodel().entity(clazz);
this.entityAlias = joinManager.addRoot(entityType, alias);
this.result = result;
this.listener = listener;
if (cteClass == null) {
this.cteType = null;
this.cteName = null;
this.isReturningEntityAliasAllowed = false;
this.returningAttributeBindingMap = new LinkedHashMap(0);
} else {
this.cteType = em.getMetamodel().entity(cteClass);
this.cteName = cteName;
// Returning the "entity" is only allowed in CTEs
this.isReturningEntityAliasAllowed = true;
this.returningAttributeBindingMap = new LinkedHashMap(cteType.getAttributes().size());
}
}
@Override
public FullSelectCTECriteriaBuilder with(Class> cteClass) {
if (!dbmsDialect.supportsWithClauseInModificationQuery()) {
throw new UnsupportedOperationException("The database does not support a with clause in modification queries!");
}
return super.with(cteClass);
}
@Override
public SelectRecursiveCTECriteriaBuilder withRecursive(Class> cteClass) {
if (!dbmsDialect.supportsWithClauseInModificationQuery()) {
throw new UnsupportedOperationException("The database does not support a with clause in modification queries!");
}
return super.withRecursive(cteClass);
}
@Override
public ReturningModificationCriteriaBuilderFactory withReturning(Class> cteClass) {
if (!dbmsDialect.supportsWithClauseInModificationQuery()) {
throw new UnsupportedOperationException("The database does not support a with clause in modification queries!");
}
return super.withReturning(cteClass);
}
protected void applyJpaReturning(StringBuilder sbSelectFrom) {
sbSelectFrom.append(" RETURNING ");
boolean first = true;
for (String attribute : returningAttributeBindingMap.values()) {
if (first) {
first = false;
} else {
sbSelectFrom.append(", ");
}
sbSelectFrom.append(attribute);
}
}
@Override
public Query getQuery() {
return getQuery(null);
}
@Override
protected Query getQuery(Map includedModificationStates) {
Query query;
// We use this to make these features only available to Hibernate as it is the only provider that supports sql replace yet
if (statementType == DbmsStatementType.INSERT
|| (hasLimit() || mainQuery.cteManager.hasCtes() || returningAttributeBindingMap.size() > 0)) {
// We need to change the underlying sql when doing a limit with hibernate since it does not support limiting insert ... select statements
// For CTEs we will also need to change the underlying sql
query = em.createQuery(getBaseQueryStringWithCheck());
Set parameterListNames = parameterManager.getParameterListNames(query);
boolean isEmbedded = this instanceof ReturningBuilder;
String[] returningColumns = getReturningColumns();
boolean shouldRenderCteNodes = renderCteNodes(isEmbedded);
List ctes = shouldRenderCteNodes ? getCteNodes(query, isEmbedded) : Collections.EMPTY_LIST;
QuerySpecification querySpecification = new ModificationQuerySpecification(
this,
query,
getCountExampleQuery(),
parameterListNames,
mainQuery.cteManager.isRecursive(),
ctes,
shouldRenderCteNodes,
isEmbedded,
returningColumns,
includedModificationStates,
returningAttributeBindingMap
);
query = new CustomSQLQuery(
querySpecification,
query,
(CommonQueryBuilder>) this,
cbf.getExtendedQuerySupport(),
parameterManager.getValuesParameters(),
parameterManager.getValuesBinders()
);
} else {
query = em.createQuery(getBaseQueryStringWithCheck());
}
parameterManager.parameterizeQuery(query);
// Don't set the values for UPDATE or DELETE statements, otherwise Datanucleus will pass through the values to the JDBC statement
if (statementType == DbmsStatementType.INSERT) {
query.setFirstResult(firstResult);
query.setMaxResults(maxResults);
}
return query;
}
public int executeUpdate() {
return getQuery().executeUpdate();
}
@Override
protected Map getModificationStates(Map, Map> explicitVersionEntities) {
Map versionEntities = explicitVersionEntities.get(entityType.getJavaType());
if (versionEntities == null) {
return null;
}
Map includedModificationStates = new HashMap();
// TODO: this needs to include the modification states based on what the dbms uses as default
boolean defaultOld = !(dbmsDialect instanceof DB2DbmsDialect);
if (defaultOld) {
for (Map.Entry entry : versionEntities.entrySet()) {
if (entry.getValue() == DbmsModificationState.NEW) {
includedModificationStates.put(DbmsModificationState.NEW, entityType.getName() + "_new");
break;
}
}
} else {
for (Map.Entry entry : versionEntities.entrySet()) {
if (entry.getValue() == DbmsModificationState.OLD) {
includedModificationStates.put(DbmsModificationState.OLD, entityType.getName() + "_old");
break;
}
}
}
return includedModificationStates;
}
protected Map getModificationStateRelatedTableNameRemappings(Map, Map> explicitVersionEntities) {
Map versionEntities = explicitVersionEntities.get(entityType.getJavaType());
if (versionEntities == null) {
return null;
}
Map tableNameRemappings = new HashMap();
// TODO: this needs to include the modification states based on what the dbms uses as default, so use a DbmsDialect method
boolean defaultOld = !(dbmsDialect instanceof DB2DbmsDialect);
if (defaultOld) {
for (Map.Entry entry : versionEntities.entrySet()) {
if (entry.getValue() == DbmsModificationState.NEW) {
tableNameRemappings.put(entry.getKey(), entityType.getName() + "_new");
}
}
} else {
for (Map.Entry entry : versionEntities.entrySet()) {
if (entry.getValue() == DbmsModificationState.OLD) {
tableNameRemappings.put(entry.getKey(), entityType.getName() + "_old");
}
}
}
return tableNameRemappings;
}
public ReturningResult executeWithReturning(String... attributes) {
return getWithReturningQuery(attributes).getSingleResult();
}
public TypedQuery> getWithReturningQuery(String... attributes) {
if (attributes == null) {
throw new NullPointerException("attributes");
}
if (attributes.length == 0) {
throw new IllegalArgumentException("Invalid empty attributes");
}
Query baseQuery = em.createQuery(getBaseQueryStringWithCheck());
List>> attributeList = getAndCheckAttributes(attributes);
TypedQuery
© 2015 - 2025 Weber Informatics LLC | Privacy Policy