2015-03-30 14 views
10

Tôi có một kiểu người dùng Hibernate được định nghĩa để chuyển đổi dữ liệu trước khi nó đi vào cơ sở dữ liệu của chúng tôi và sau đó bỏ chuyển đổi nó khi được đọc lại từ db. Điều này hoạt động tốt khi tôi chèn một hàng hoặc nhận hàng bằng cách sử dụng ID của hàng hoặc một số cách khác để truy vấn hàng. Tuy nhiên, khi tôi cố gắng sử dụng một truy vấn để tìm một kỷ lục, tham số ràng buộc dường như thất bại:Hibernate - Không thể thực hiện truy vấn bằng UserType trong mệnh đề where

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)] 

tôi đã cố gắng thực hiện LiteralTypeobjectToSQLString phương pháp nhưng nó không giống như phương pháp này là bao giờ gọi.

Là một ví dụ đơn giản:

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; 
    } 
} 

Thực thể trông giống như:

@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; 

    //... 
} 

truy vấn của tôi:

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

Trong truy vấn của bạn ("nơi b.transformed =? 1") sau dấu chấm hỏi bạn có 1, đó có phải là lỗi đánh máy trong thời điểm đăng câu hỏi này hay nó thực sự tồn tại trong mã của bạn không? :) – Bikku

+0

Rin, rằng "? 1" là trong mã. Tôi tin rằng đó là chính xác - đó là cách thay thế tham số hoạt động. –

Trả lời

2

Tôi nghĩ rằng bạn cần phải thay đổi lớp trả về:

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

nên là:

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

Trong các tài liệu (https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/usertype/UserType.html#returnedClass()):

trả lạiClass

Lớp returnedClass()

Lớp trả về bởi nullSafeGet(). Returns: Lớp

và nullSafeGet của bạn dường như được trở về một String.

+0

Điều này đã hiệu quả. Hibernate đang sử dụng nullSafeSet để lấy String nó cần để ném vào truy vấn. Nó dường như không được sử dụng phương pháp objectToSQLString ở tất cả vì vậy nó có thể có thể không thực hiện LiteralType. –

1

Với Data mùa xuân, bạn có thể thực hiện một custom query implementation và bạn có thể unwrap EntityManager đến phiên Hibernate và sau đó cung cấp Custom Type E mà bạn đã tạo cho truy vấn của bạn:

@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(); 
} 
Các vấn đề liên quan