2014-07-01 17 views
7

Giả sử tôi có một Hibernate/JPA Entity như sau:Có cách nào để truy vấn kho lưu trữ PostgreSQL với Hibernate/JPQL không?

@Entity 
public class FooEntity { 

    ... 

    @Type(type = "hstore") 
    HashMap<String, String> tags; 
} 

... và Type hstore là một việc thực hiện loại người dùng đơn giản từ this tài nguyên.

Có cách nào để truy cập hstore trong một truy vấn JPQL tương tự như Mã giả này:

SELECT f FROM FooEntity f WHERE f.tags CONTAINS KEY(:key) 

Trả lời

1

Hibernate cung cấp một trừu tượng truy vấn phổ biến trên nhiều DBS do đó, một cú pháp phi SQL là khó có thể được trừu tượng ra.

Tôi sẽ tìm một truy vấn gốc để tìm nạp các id và sử dụng các truy vấn đó để nhận các thực thể Hibernate nếu bạn thực sự cần những thứ đó.

Nếu bạn chỉ quan tâm đến dự báo hơn truy vấn gốc là lựa chọn tốt nhất của bạn.

2

Bạn cũng có thể chỉ cần tạo Hibernate org.hibernate.usertype.UserType. Bạn mở rộng lớp đó; một ví dụ từ thực hiện riêng của chúng tôi:

public class HstoreUserType implements UserType { 

/** 
* PostgreSQL {@code hstore} field separator token. 
*/ 
private static final String HSTORE_SEPARATOR_TOKEN = "=>"; 

/** 
* {@link Pattern} used to find and split {@code hstore} entries. 
*/ 
private static final Pattern HSTORE_ENTRY_PATTERN = Pattern.compile(String.format("\"(.*)\"%s\"(.*)\"", HSTORE_SEPARATOR_TOKEN)); 

/** 
* The PostgreSQL value for the {@code hstore} data type. 
*/ 
public static final int HSTORE_TYPE = 1111; 

@Override 
public int[] sqlTypes() { 
    return new int[] { HSTORE_TYPE }; 
} 

@SuppressWarnings("rawtypes") 
@Override 
public Class returnedClass() { 
    return Map.class; 
} 

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

@Override 
public int hashCode(final Object x) throws HibernateException { 
    return x.hashCode(); 
} 

@Override 
public Object nullSafeGet(final ResultSet rs, final String[] names, 
     final SessionImplementor session, final Object owner) 
     throws HibernateException, SQLException { 
    return convertToEntityAttribute(rs.getString(names[0])); 
} 

@SuppressWarnings("unchecked") 
@Override 
public void nullSafeSet(final PreparedStatement st, final Object value, final int index, 
     final SessionImplementor session) throws HibernateException, SQLException { 
    st.setObject(index, convertToDatabaseColumn((Map<String,Object>)value), HSTORE_TYPE); 

} 

@SuppressWarnings("unchecked") 
@Override 
public Object deepCopy(final Object value) throws HibernateException { 
    return new HashMap<String,Object>(((Map<String,Object>)value)); 
} 

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

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

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

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


private String convertToDatabaseColumn(final Map<String, Object> attribute) { 
    final StringBuilder builder = new StringBuilder(); 
    for (final Map.Entry<String, Object> entry : attribute.entrySet()) { 
     if(builder.length() > 1) { 
      builder.append(", "); 
     } 
     builder.append("\""); 
     builder.append(entry.getKey()); 
     builder.append("\""); 
     builder.append(HSTORE_SEPARATOR_TOKEN); 
     builder.append("\""); 
     builder.append(entry.getValue().toString()); 
     builder.append("\""); 
    } 
    return builder.toString(); 
} 

private Map<String, Object> convertToEntityAttribute(final String dbData) { 
    final Map<String, Object> data = new HashMap<String, Object>(); 
    if (dbData != null) { 
     final StringTokenizer tokenizer = new StringTokenizer(dbData, ","); 
     while(tokenizer.hasMoreTokens()) { 
      final Matcher matcher = HSTORE_ENTRY_PATTERN.matcher(tokenizer.nextToken().trim()); 
      if(matcher.find()) { 
       data.put(matcher.group(1), matcher.group(2)); 
      } 
     } 
    } 
    return data; 
} 

}

Bây giờ bạn có thể sử dụng nó trong vòng trong Entity đậu như vậy:

@Entity 
@Table(name="YourEntityBeanTable") 
@TypeDefs({ 
    @TypeDef(name = "hstore", typeClass = HstoreUserType.class) 
}) 

public class YourEntityBean { 

..... 

    @Type(type = "hstore")  
    @Column(name= "an_hstore_column", columnDefinition = "hstore") 
    private Map<String, String> anHStoreColumn = new HashMap<>(); 



} 
+0

không thể sử dụng hstore lĩnh vực với điều kiện nơi ... –

Các vấn đề liên quan