2016-09-21 26 views
6

vấn đề của chúng tôi là chúng tôi không thể nhận được dữ liệu (bao gồm trống chuỗi với chiều dài 0) từ một cơ sở dữ liệu di sản do một nguồn gốc StringIndexOutOfBoundsExceptiion từ Hibernate của CharacterTypeDescriptor. Chúng tôi muốn thay đổi hành vi của Hibernate để xử lý đúng các chuỗi trống.Làm thế nào để thay đổi Hibernate CharacterTypeDescriptor để xử lý cột rỗng giá trị

Ví dụ dữ liệu:

1, 'Berlin', 17277, '', 'aUser' 
2, 'London', 17277, '', 'anotherUser' 

Chúng tôi sử dụng ngủ đông với javax.persistence.Query.

String sql = "SELECT * FROM table"; 
Query query = entityManager.createNativeQuery(sql); 
List resultList = query.getResultList(); 

Điều này dẫn đến một StringIndexOutOfBoundsException với gốc của nó là đoạn mã sau từ Hibernate:

if (String.class.isInstance(value)) { 
    final String str = (String) value; 
    return Character.valueOf(str.charAt(0)); // this fails, as there is no char at position 0 
} 

này được xác nhận bởi a post on the hibernate forums.

Chúng tôi không có tùy chọn nâng cấp ngủ đông từ phiên bản lỗi này và tìm cách thay đổi ánh xạ của Hibernate.

Chúng tôi không thể sử dụng PreparedStatements hoặc JDBC-Connections thuần túy cũng như JPA-Entities.

Thay đổi cơ sở dữ liệu cũ cũng không thể thực hiện được. Câu lệnh SQL hoạt động hoàn hảo bằng cách sử dụng DBVisualizer.

Có cách nào để thay đổi cách ánh xạ chuỗi của Hibernate không?

+0

Tôi chỉ cần hỏi, tại sao các địa ngục không thể bạn sử dụng bất kỳ goodies Hibernate thực sự cung cấp? – rorschach

+0

Vì hibernate là "không được hỗ trợ". Vì vậy, chúng tôi được yêu cầu sử dụng SQL cấp thấp nhất có thể. – michaelbahr

Trả lời

5

Đông peasy!

Thực tế, vì đây là một câu hỏi rất hay nên tôi quyết định viết an article to demonstrate how easily you can achieve this goal using a custom Hibernate Type.

Trước tiên, bạn cần phải xác định một ImmutableType:

public abstract class ImmutableType<T> implements UserType { 

    private final Class<T> clazz; 

    protected ImmutableType(Class<T> clazz) { 
     this.clazz = clazz; 
    } 

    @Override 
    public Object nullSafeGet(
     ResultSet rs, 
     String[] names, 
     SharedSessionContractImplementor session, 
     Object owner) 
     throws SQLException { 
     return get(rs, names, session, owner); 
    } 

    @Override 
    public void nullSafeSet(
     PreparedStatement st, 
     Object value, 
     int index, 
     SharedSessionContractImplementor session) 
     throws SQLException { 
     set(st, clazz.cast(value), index, session); 
    } 

    protected abstract T get(
     ResultSet rs, 
     String[] names, 
     SharedSessionContractImplementor session, 
     Object owner) throws SQLException; 

    protected abstract void set(
     PreparedStatement st, 
     T value, 
     int index, 
     SharedSessionContractImplementor session) 
     throws SQLException; 


    @Override 
    public Class<T> returnedClass() { 
     return clazz; 
    } 

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

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

    @Override 
    public Object deepCopy(Object value) { 
     return value; 
    } 

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

    @Override 
    public Serializable disassemble(Object o) { 
     return (Serializable) o; 
    } 

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

    @Override 
    public Object replace(
     Object o, 
     Object target, 
     Object owner) { 
     return o; 
    } 
} 

Bây giờ, chúng ta có thể di chuyển để xác định thực tế CharacterType:

public class CharacterType 
    extends ImmutableType<Character> { 

    public CharacterType() { 
     super(Character.class); 
    } 

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

    @Override 
    public Character get(
     ResultSet rs, 
     String[] names, 
     SharedSessionContractImplementor session, 
     Object owner) 
     throws SQLException { 
     String value = rs.getString(names[0]); 
     return (value != null && value.length() > 0) ? 
      value.charAt(0) : null; 
    } 

    @Override 
    public void set(
     PreparedStatement st, 
     Character value, 
     int index, 
     SharedSessionContractImplementor session) 
     throws SQLException { 
     if (value == null) { 
      st.setNull(index, Types.CHAR); 
     } else { 
      st.setString(index, String.valueOf(value)); 
     } 
    } 
} 

Việc lập bản đồ thực thể trông như thế này:

@Entity(name = "Event") 
@Table(name = "event") 
public class Event { 

    @Id 
    @GeneratedValue 
    private Long id; 

    @Type(type = "com.vladmihalcea.book.hpjp.hibernate.type.CharacterType") 
    @Column(name = "event_type") 
    private Character type; 

    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    public Character getType() { 
     return type; 
    } 

    public void setType(Character type) { 
     this.type = type; 
    } 
} 

Và giả sử chúng ta có các hàng trong bảng sau:

INSERT INTO event (id, event_type) VALUES (1, 'abc');  
INSERT INTO event (id, event_type) VALUES (2, ''); 
INSERT INTO event (id, event_type) VALUES (3, 'b'); 

Khi đọc tất cả các thực thể:

doInJPA(entityManager -> { 
    List<Event> events = entityManager.createQuery(
     "select e from Event e", Event.class) 
    .getResultList(); 
    for(Event event : events) { 
     LOGGER.info("Event type: {}", event.getType()); 
    } 
}); 

Bạn sẽ nhận được kết quả mong muốn:

Event type: a 
Event type: 
Event type: b 

Kiểm tra mã nguồn trên GitHub.

1

Hãy xem xét tất cả các hạn chế bạn có, tôi nghĩ giải pháp dễ nhất (nhưng hackiest) là viết lại truy vấn SELECT để kiểm tra xem giá trị cột có trống không và trong trường hợp đó trả về một số văn bản giữ chỗ .. hoặc null nếu Hibernate có thể xử lý thay vào đó.

+0

Đã làm điều đó và có vẻ như nó hoạt động. Sẽ đưa mã lên sau. Cảm ơn! – michaelbahr

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