2014-06-08 15 views
5

Ho una tabella denominata in MySQL con solo due colonne user_group_id e group_id (entrambi sono di tipo VARCHAR). Entrambe queste colonne formano insieme una chiave primaria composita.clausola IN con una chiave primaria composita in criteri JPA

Ho bisogno di eseguire una dichiarazione utilizzando una sottoselezione IN() per selezionare le righe in base a un elenco di valori passati alla query.

@Override 
@SuppressWarnings("unchecked") 
public List<GroupTable> getList(List<GroupTable> list) 
{ 
    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder(); 
    CriteriaQuery<GroupTable> criteriaQuery=criteriaBuilder.createQuery(GroupTable.class); 
    Root<GroupTable> root = criteriaQuery.from(entityManager.getMetamodel().entity(GroupTable.class)); 
    criteriaQuery.where(root.in(list)); 
    return entityManager.createQuery(criteriaQuery).getResultList(); 
} 

L'implementazione produce la seguente query.

SELECT group_id, 
     user_group_id 
FROM projectdb.group_table 
WHERE ((?, ?) IN ((?, ?), (?, ?))) 

/*Binding parameters.*/ 
bind => [null, null, ROLE_AAA, aaa, ROLE_BBB, aaa] 

Si prega di notare che i primi due parametri che sono circa la chiave composita in sé sono null. Dovrebbero essere rispettivamente user_group_id e group_id.

Perché non vengono sostituiti nell'elenco dei parametri?


Mentre io non sono interessati a formare una chiave primaria composta in una tabella, questo è (probabile) obbligatorio per JAAS sto utilizzando per l'autenticazione.

In questo scenario, la query restituisce lo stesso elenco fornito dal database che è inutile nella realtà. In realtà ho bisogno di questa query per l'eliminazione di più righe.

risposta

3

provare questo

 CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 
     CriteriaQuery<GroupTable> cq = cb.createQuery(GroupTable.class); 
     Root<GroupTable> r = cq.from(GroupTable.class); 
     Expression<EntityPK> exp = r.get("id"); //EntityPK is your primary composite key class and id is the property name of primary key in GroupTable entity 
     Predicate predicate = exp.in(list); 
     cq.select(r).where(predicate); 

     entityManager.createQuery(cq).getResultList(); 

Ho una tabella seguente con sottostante struttura

create table EntityA (
     col1 integer not null, 
     col2 integer not null, 
     description varchar(255), 
     primary key (col1, col2) 
    ) 

seguito sono l'entità e le classi principali compositi

@Entity 
public class EntityA implements Serializable { 

    @EmbeddedId 
    private EntityPK id; 
    private String description; 

// getters, setteres  
    ........................... 
    ............................ 


    } 


@Embeddable 
public class EntityPK implements Serializable { 

    private int col1; 
    private int col2; 

// getters, setters, hashcode, equals etc 

Il mio codice di prova è

CriteriaBuilder cb = em.getCriteriaBuilder(); 
     CriteriaQuery<EntityA> cq = cb.createQuery(EntityA.class); 
     Root<EntityA> r = cq.from(EntityA.class); 
     Expression<EntityPK> exp = r.get("id"); 
     Predicate predicate = exp.in(list); 
     cq.select(r).where(predicate); 
     em.createQuery(cq).getResultList(); 

Lo SQL risultante è

select 
     entitya0_.col1 as col1_0_, 
     entitya0_.col2 as col2_0_, 
     entitya0_.description as descript3_0_ 
    from 
     EntityA entitya0_ 
    where 
     entitya0_.col1=? 
     and entitya0_.col2=? 
     or entitya0_.col1=? 
     and entitya0_.col2=? 
     or entitya0_.col1=? 
     and entitya0_.col2=? 
+1

Non è possibile produrre una query come 'WHERE ((user_group_id, group_id) IN ((?,?), (?,?)))'? MySQL 5.x supporta questo. Sarebbe molto meglio, se possibile :) Grazie mille comunque. – Tiny

+0

Hai testato la query in Hibernate ma l'errore si trova in Eclipselink. – zbig

3

questa è una caratteristica mancante in collegamento eclissi. Ho devlopped una patch per questo

/** ***************************************************************************** 
* 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 <[email protected]> - 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; 

/** 
* <p> 
* <b>Purpose</b>: Expression SQL printer. 
* <p> 
* <b>Responsibilities</b>:<ul> 
* <li> Print an expression in SQL format. 
* <li> Replaces FIELD types with field names from the descriptor. 
* <li> Replaces PARAMETER types with row or object values. 
* <li> Calls accessor to print primitive types. 
* </ul> 
* <p> 
* @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); 
    } 
} 

La patch è delimitata da // inizio del cerotto n e // fine della toppa n cercherò di sumbmit esso monte ma potrebbe richiede tempi

Problemi correlati