2015-03-30 5 views
10

Ich habe einen Hibernate UserType definiert, um Daten zu transformieren, bevor es in unsere Datenbank geht, und es dann umzuwandeln, wenn es von der Datenbank zurückgelesen wird. Dies funktioniert gut, wenn ich eine Zeile einfüge oder Zeilen mithilfe der ID der Zeile oder einer anderen Möglichkeit zur Abfrage der Zeile abrufe. Allerdings, wenn ich versuche, eine Abfrage zu verwenden, um einen Datensatz zu finden, scheint die Parameterbindung zum Scheitern verurteilt:Hibernate - Abfrage kann nicht mit einem UserType in Where-Klausel ausgeführt werden

org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [thisIsTheSearchString] did not match expected type [com.xxx.MyUserType (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [thisIsTheSearchString] did not match expected type [com.xxx.MyUserType (n/a)] 

Ich versuchte LiteralType und die objectToSQLString Verfahren implementiert, aber es sieht nicht wie diese Methode immer genannt wird.

Als vereinfachtes Beispiel:

public class MyUserType implements UserType, LiteralType { 

    @Override 
    public int[] sqlTypes() { 
     return new int[] { 
       Types.VARCHAR 
     }; 
    } 

    @Override 
    public Class returnedClass() { 
     return MyUserType.class; 
    } 

    @Override 
    public boolean equals(Object x, Object y) throws HibernateException { 
     return ObjectUtils.equals(x, y); 
    } 

    @Override 
    public int hashCode(Object x) throws HibernateException { 
     assert (x != null); 
     return x.hashCode(); 
    } 

    @Override 
    public Object nullSafeGet(
      ResultSet rs, 
      String[] names, 
      SessionImplementor session, 
      Object owner) 
        throws HibernateException, SQLException 
    { 
     assert names.length == 1; 
     return untransform(rs.getString(names[0]);); 
    } 

    String transform(String untransformed) { 
     //... 
    } 

    String untransform(String transformed) { 
     //... 
    } 

    @Override 
    public void nullSafeSet(
      PreparedStatement st, 
      Object value, 
      int index, 
      SessionImplementor session) 
        throws HibernateException, SQLException 
    { 
     if (value == null) { 
      st.setNull(index, Types.VARCHAR); 
     } else { 
      final String untransformed = (String)value; 

      return transform(untransformed); 
     } 
    } 

    @Override 
    public Object deepCopy(Object value) throws HibernateException { 
     if (value == null) { 
      return null; 
     } 
     return (String)value; 
    } 

    @Override 
    public boolean isMutable() { 
     return true; 
    } 

    @Override 
    public Serializable disassemble(Object value) throws HibernateException { 
     return (Serializable) deepCopy(value); 
    } 

    @Override 
    public Object assemble(Serializable cached, Object owner) 
      throws HibernateException { 
     return deepCopy(cached); 
    } 

    @Override 
    public Object replace(Object original, Object target, Object owner) 
      throws HibernateException { 
     return deepCopy(original); 
    } 

    // THIS NEVER GETS CALLED 
    @Override 
    public String objectToSQLString(Object value, Dialect dialect) 
      throws Exception 
    { 
     if (value == null) { 
      return null; 
     } 

     String transformed = transform((String)value); 

     StringType stringType = new StringType(); 
     String sqlString = stringType.objectToSQLString(transformed, dialect); 

     return sqlString; 
    } 
} 

Das Unternehmen sieht so aus:

@Entity 
@Table(name = "blah_blah") 
@TypeDefs(value = { @TypeDef(name = "transformedText", typeClass = MyUserType.class)}) 
public class BlahBlah implements Serializable, Persistable<Long> { 

    //... 

    @Column(name = "transformed") 
    @Type(type = "transformedText") 
    String transformed; 

    //... 
} 

Meine Frage:

@Query(value = 
     "select b " + 
     "from BlahBlah b " + 
     "where b.transformed = ?1 ") 
public List<BlahBlah> findTransformed(String text); 
+0

In Ihrer Abfrage ("wo b.transformiert =? 1") nach Fragezeichen haben Sie 1, ist es ein Tippfehler in der Zeit des Veröffentlichens dieser Frage oder ist es wirklich in Ihrem Code vorhanden? :) – Bikku

+0

Rin, das "? 1" ist im Code. Ich glaube, das ist richtig - so funktioniert die Parametersubstitution. –

Antwort

2

Ich glaube, Sie die zurückgegebene Klasse ändern müssen:

@Override 
public Class returnedClass() { 
    return MyUserType.class; 
} 

sein sollte:

@Override 
public Class returnedClass() { 
    return String.class; 
} 

In der Dokumentation (https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/usertype/UserType.html#returnedClass()):

returnedClass

Klasse returnedClass()

Die Klasse zurück von nullSafeGet(). Returns: Klasse

und Ihre nullSafeGet erscheint ein String zurückkehrt zu werden.

+0

Das hat funktioniert. Hibernate verwendet nullSafeSet, um die Zeichenfolge abzurufen, die in die Abfrage eingefügt werden muss. Es scheint nicht die objectToSQLString-Methode überhaupt zu verwenden, so dass es möglich sein kann, LiteralType nicht zu implementieren. –

1

mit Spring Data Sie eine custom query implementation implementieren und Sie können auspacken die EntityManager zu einer Hibernate-Sitzung, und geben Sie dann den benutzerdefinierten Typ e Sie auf Ihre Anfrage erstellt:

@PersistenceContext 
private EntityManager entityManager; 

public List<BlahBlah> findTransformed(String text) { 
    Session session = entityManager.unwrap(Session.class); 

    TypeHelper typeHelper = session.getSessionFactory().getTypeHelper(); 

    List<BlahBlah> result = (List<BlahBlah>) session.createQuery(
     "select b " + 
     "from BlahBlah b " + 
     "where b.transformed = :transformed ") 
    .setParameter("transformed", text, typeHelper.custom(MyUserType.class)) 
    .list(); 
} 
Verwandte Themen