IN clause with a composite primary key in JPA criteria

前端 未结 3 570
离开以前
离开以前 2021-01-05 09:13

I have a table named group_table in MySQL with only two columns user_group_id and group_id (both of them are of type VARCHAR

3条回答
  •  北海茫月
    2021-01-05 09:49

    this is a missing feature in eclipse link. I have devlopped a patch for this

    /** *****************************************************************************
     * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.
     * This program and the accompanying materials are made available under the
     * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
     * which accompanies this distribution.
     * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
     * and the Eclipse Distribution License is available at
     * http://www.eclipse.org/org/documents/edl-v10.php.
     *
     * Contributors:
     * Oracle - initial API and implementation from Oracle TopLink
     * Nicolas Marcotte  - patch for IN on composite keys comming from expression builder 
    
     ***************************************************************************** */
    package org.eclipse.persistence.internal.expressions;
    
    import java.io.*;
    import java.util.*;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.eclipse.persistence.internal.helper.*;
    import org.eclipse.persistence.internal.sessions.AbstractSession;
    import org.eclipse.persistence.queries.*;
    import org.eclipse.persistence.exceptions.*;
    import org.eclipse.persistence.expressions.*;
    import org.eclipse.persistence.internal.databaseaccess.*;
    import org.eclipse.persistence.internal.sessions.AbstractRecord;
    
    /**
     * 

    * Purpose: Expression SQL printer. *

    * Responsibilities:

      *
    • Print an expression in SQL format. *
    • Replaces FIELD types with field names from the descriptor. *
    • Replaces PARAMETER types with row or object values. *
    • Calls accessor to print primitive types. *
    *

    * @author Dorin Sandu * @since TOPLink/Java 1.0 */ public class ExpressionSQLPrinter { /** * Stores the current session. The session accessor * is used to print all the primitive types. */ protected AbstractSession session; /** * Stores the current platform to access platform specific functions. */ protected DatabasePlatform platform; /** * Stores the call being created. */ protected SQLCall call; /** * Stores the row. Used to print PARAMETER nodes. */ protected AbstractRecord translationRow; /** * Indicates whether fully qualified field names * (owner + table) should be used or not. */ protected boolean shouldPrintQualifiedNames; // What we write on protected Writer writer; /** Used for distincts in functions. */ protected boolean requiresDistinct; // Used in figuring out when to print a comma in the select line protected boolean isFirstElementPrinted; private final ExpressionBuilder builder; public ExpressionSQLPrinter(AbstractSession session, AbstractRecord translationRow, SQLCall call, boolean printQualifiedNames, ExpressionBuilder builder) { this.session = session; this.translationRow = translationRow; this.call = call; this.shouldPrintQualifiedNames = printQualifiedNames; // reference session's platform directly if builder or builder's descriptor is null if (builder == null || builder.getDescriptor() == null) { this.platform = getSession().getPlatform(); } else { this.platform = (DatabasePlatform) getSession().getPlatform(builder.getDescriptor().getJavaClass()); } this.requiresDistinct = false; this.builder = builder; isFirstElementPrinted = false; } /** * Return the call. */ public SQLCall getCall() { return call; } /** * INTERNAL: * Return the database platform specific information. */ public DatabasePlatform getPlatform() { return this.platform; } protected AbstractSession getSession() { return session; } /** * INTERNAL: * Return the row for translation */ protected AbstractRecord getTranslationRow() { return translationRow; } public Writer getWriter() { return writer; } /** * INTERNAL: * Used in figuring out when to print a comma in the select clause */ public boolean isFirstElementPrinted() { return isFirstElementPrinted; } public void printExpression(Expression expression) { translateExpression(expression); } public void printField(DatabaseField field) { if (field == null) { return; } //start of patch 1 //resolve alias if is was not already done if (builder.getTableAliases() != null) { DatabaseTable keyAtValue = builder.getTableAliases().keyAtValue(field.getTable()); if (keyAtValue != null) { field.setTableName(keyAtValue.getName()); } } //end of patch 1 try { // Print the field using either short or long notation i.e. owner + table name. if (shouldPrintQualifiedNames()) { getWriter().write(field.getQualifiedNameDelimited(platform)); } else { getWriter().write(field.getNameDelimited(platform)); } } catch (IOException exception) { throw ValidationException.fileError(exception); } } public void printParameter(ParameterExpression expression) { try { final Logger logger = LogManager.getLogger(); getCall().appendTranslationParameter(getWriter(), expression, getPlatform(), getTranslationRow()); } catch (IOException exception) { throw ValidationException.fileError(exception); } } public void printParameter(DatabaseField field) { getCall().appendTranslation(getWriter(), field); } public void printPrimitive(Object value) { if (value instanceof Collection) { printValuelist((Collection) value); return; } session.getPlatform().appendLiteralToCall(getCall(), getWriter(), value); } public void printNull(ConstantExpression nullValueExpression) { if (session.getPlatform().shouldBindLiterals()) { DatabaseField field = null; Expression localBase = nullValueExpression.getLocalBase(); if (localBase.isFieldExpression()) { field = ((FieldExpression) localBase).getField(); } else if (localBase.isQueryKeyExpression()) { field = ((QueryKeyExpression) localBase).getField(); } session.getPlatform().appendLiteralToCall(getCall(), getWriter(), field); } else { session.getPlatform().appendLiteralToCall(getCall(), getWriter(), null); } } public void printString(String value) { try { getWriter().write(value); } catch (IOException exception) { throw ValidationException.fileError(exception); } } public void printValuelist(Collection values) { try { getWriter().write("("); Iterator valuesEnum = values.iterator(); while (valuesEnum.hasNext()) { Object value = valuesEnum.next(); // Support nested arrays for IN. if (value instanceof Collection) { printValuelist((Collection) value); } else if (value instanceof Expression) { ((Expression) value).printSQL(this); //start of patch 2 } else if (value instanceof DatabaseField) { printExpression(builder.getField((DatabaseField) value)); //end of patch 2 } else { session.getPlatform().appendLiteralToCall(getCall(), getWriter(), value); } if (valuesEnum.hasNext()) { getWriter().write(", "); } } getWriter().write(")"); } catch (IOException exception) { throw ValidationException.fileError(exception); } } /* * Same as printValuelist, but allows for collections containing expressions recursively */ public void printList(Collection values) { try { getWriter().write("("); Iterator valuesEnum = values.iterator(); while (valuesEnum.hasNext()) { Object value = valuesEnum.next(); if (value instanceof Expression) { ((Expression) value).printSQL(this); } else { session.getPlatform().appendLiteralToCall(getCall(), getWriter(), value); } if (valuesEnum.hasNext()) { getWriter().write(", "); } } getWriter().write(")"); } catch (IOException exception) { throw ValidationException.fileError(exception); } } /** * If a distinct has been set the DISTINCT clause will be printed. * This is required for batch reading. */ public boolean requiresDistinct() { return requiresDistinct; } protected void setCall(SQLCall call) { this.call = call; } /** * INTERNAL: * Used in figuring out when to print a comma in the select clause */ public void setIsFirstElementPrinted(boolean isFirstElementPrinted) { this.isFirstElementPrinted = isFirstElementPrinted; } /** * If a distinct has been set the DISTINCT clause will be printed. * This is required for batch reading. */ public void setRequiresDistinct(boolean requiresDistinct) { this.requiresDistinct = requiresDistinct; } protected void setSession(AbstractSession theSession) { session = theSession; } protected void setShouldPrintQualifiedNames(boolean shouldPrintQualifiedNames) { this.shouldPrintQualifiedNames = shouldPrintQualifiedNames; } /** * INTERNAL: * Set the row for translation */ protected void setTranslationRow(AbstractRecord theRow) { translationRow = theRow; } public void setWriter(Writer writer) { this.writer = writer; } public boolean shouldPrintParameterValues() { return getTranslationRow() != null; } protected boolean shouldPrintQualifiedNames() { return shouldPrintQualifiedNames; } /** * Translate an expression i.e. call the appropriate * translation method for the expression based on its * type. The translation method is then responsible * for translating the subexpressions. */ protected void translateExpression(Expression theExpression) { theExpression.printSQL(this); } }

    The patch is delimited by //start of patch n and //end of patch n I will try to sumbmit it upstream but it might takes times

提交回复
热议问题