Tôi có thể thiết lập JPA / hibernate để duy trì Boolean
các loại Y/N
không? Trong cơ sở dữ liệu (cột được định nghĩa là varchar2(1)
. Nó hiện đang lưu trữ chúng dưới dạng 0/1
. Cơ sở dữ liệu là Oracle.
Câu trả lời:
Cách duy nhất tôi đã tìm ra cách làm điều này là có hai thuộc tính cho lớp của tôi. Một làm boolean cho API lập trình không được bao gồm trong ánh xạ. Nó tham chiếu getter và setter một biến char riêng là Y / N. Sau đó, tôi có một thuộc tính được bảo vệ khác được bao gồm trong ánh xạ ngủ đông và nó getters và setters tham chiếu trực tiếp đến biến private char.
CHỈNH SỬA: Như đã chỉ ra, có các giải pháp khác được tích hợp trực tiếp vào Hibernate. Tôi để lại câu trả lời này vì nó có thể hoạt động trong các tình huống mà bạn đang làm việc với một trường kế thừa không hoạt động tốt với các tùy chọn được tích hợp sẵn. Trên hết, không có hậu quả tiêu cực nghiêm trọng nào đối với cách tiếp cận này.
Hibernate có kiểu "yes_no" được tích hợp sẵn để làm những gì bạn muốn. Nó ánh xạ tới cột CHAR (1) trong cơ sở dữ liệu.
Lập bản đồ cơ bản: <property name="some_flag" type="yes_no"/>
Ánh xạ chú thích (phần mở rộng ngủ đông):
@Type(type="yes_no")
public boolean getFlag();
Đây là JPA thuần túy mà không sử dụng getters / setters. Kể từ năm 2013/2014, đây là câu trả lời tốt nhất mà không cần sử dụng bất kỳ chú thích cụ thể Hibernate nào, nhưng xin lưu ý rằng giải pháp này là JPA 2.1 và không có sẵn khi câu hỏi được hỏi lần đầu tiên:
@Entity
public class Person {
@Convert(converter=BooleanToStringConverter.class)
private Boolean isAlive;
...
}
Và sau đó:
@Converter
public class BooleanToStringConverter implements AttributeConverter<Boolean, String> {
@Override
public String convertToDatabaseColumn(Boolean value) {
return (value != null && value) ? "Y" : "N";
}
@Override
public Boolean convertToEntityAttribute(String value) {
return "Y".equals(value);
}
}
Biên tập:
Việc triển khai ở trên coi bất kỳ điều gì khác với ký tự "Y", bao gồm null
, như false
. Đúng không? Một số người ở đây cho rằng điều này không chính xác, và tin rằng null
trong cơ sở dữ liệu phải là null
Java.
Nhưng nếu bạn trả về null
bằng Java, nó sẽ cho bạn NullPointerException
biết nếu trường của bạn là boolean nguyên thủy . Nói cách khác, trừ một số lĩnh vực của bạn thực sự sử dụng lớp Boolean tốt nhất để xem xét null
như false
, và sử dụng thực hiện ở trên. Sau đó, Hibernate sẽ không tạo ra bất kỳ ngoại lệ nào bất kể nội dung của cơ sở dữ liệu.
Và nếu bạn muốn chấp nhận null
và phát ra các ngoại lệ nếu nội dung của cơ sở dữ liệu không hoàn toàn chính xác, thì tôi đoán bạn không nên chấp nhận bất kỳ ký tự nào ngoài "Y", "N" và null
. Hãy làm cho nó nhất quán và không chấp nhận bất kỳ biến thể nào như "y", "n", "0" và "1", điều này sẽ chỉ khiến cuộc sống của bạn sau này khó khăn hơn. Đây là cách triển khai nghiêm ngặt hơn:
@Override
public String convertToDatabaseColumn(Boolean value) {
if (value == null) return null;
else return value ? "Y" : "N";
}
@Override
public Boolean convertToEntityAttribute(String value) {
if (value == null) return null;
else if (value.equals("Y")) return true;
else if (value.equals("N")) return false;
else throw new IllegalStateException("Invalid boolean character: " + value);
}
Và một tùy chọn khác, nếu bạn muốn cho phép null
trong Java nhưng không cho phép trong cơ sở dữ liệu:
@Override
public String convertToDatabaseColumn(Boolean value) {
if (value == null) return "-";
else return value ? "Y" : "N";
}
@Override
public Boolean convertToEntityAttribute(String value) {
if (value.equals("-") return null;
else if (value.equals("Y")) return true;
else if (value.equals("N")) return false;
else throw new IllegalStateException("Invalid boolean character: " + value);
}
Y
, N
và T
. Tôi cũng không chắc người ta nên bỏ qua trường hợp có giá trị null do chuyển đổi.
Tôi đã sử dụng khái niệm từ câu trả lời được đăng bởi @marcg và nó hoạt động tốt với JPA 2.1. Mã của anh ấy không đúng lắm, vì vậy tôi đã đăng bản triển khai đang làm việc của mình. Điều này sẽ chuyển đổi Boolean
các trường thực thể thành một cột ký tự Y / N trong cơ sở dữ liệu.
Từ lớp thực thể của tôi:
@Convert(converter=BooleanToYNStringConverter.class)
@Column(name="LOADED", length=1)
private Boolean isLoadedSuccessfully;
Lớp chuyển đổi của tôi:
/**
* Converts a Boolean entity attribute to a single-character
* Y/N string that will be stored in the database, and vice-versa
*
* @author jtough
*/
public class BooleanToYNStringConverter
implements AttributeConverter<Boolean, String> {
/**
* This implementation will return "Y" if the parameter is Boolean.TRUE,
* otherwise it will return "N" when the parameter is Boolean.FALSE.
* A null input value will yield a null return value.
* @param b Boolean
*/
@Override
public String convertToDatabaseColumn(Boolean b) {
if (b == null) {
return null;
}
if (b.booleanValue()) {
return "Y";
}
return "N";
}
/**
* This implementation will return Boolean.TRUE if the string
* is "Y" or "y", otherwise it will ignore the value and return
* Boolean.FALSE (it does not actually look for "N") for any
* other non-null string. A null input value will yield a null
* return value.
* @param s String
*/
@Override
public Boolean convertToEntityAttribute(String s) {
if (s == null) {
return null;
}
if (s.equals("Y") || s.equals("y")) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}
}
Biến thể này cũng rất thú vị nếu bạn yêu thích các biểu tượng cảm xúc và cảm thấy mệt mỏi với Y / N hoặc T / F trong cơ sở dữ liệu của mình. Trong trường hợp này, cột cơ sở dữ liệu của bạn phải là hai ký tự thay vì một. Có lẽ không phải là một vấn đề lớn.
/**
* Converts a Boolean entity attribute to a happy face or sad face
* that will be stored in the database, and vice-versa
*
* @author jtough
*/
public class BooleanToHappySadConverter
implements AttributeConverter<Boolean, String> {
public static final String HAPPY = ":)";
public static final String SAD = ":(";
/**
* This implementation will return ":)" if the parameter is Boolean.TRUE,
* otherwise it will return ":(" when the parameter is Boolean.FALSE.
* A null input value will yield a null return value.
* @param b Boolean
* @return String or null
*/
@Override
public String convertToDatabaseColumn(Boolean b) {
if (b == null) {
return null;
}
if (b) {
return HAPPY;
}
return SAD;
}
/**
* This implementation will return Boolean.TRUE if the string
* is ":)", otherwise it will ignore the value and return
* Boolean.FALSE (it does not actually look for ":(") for any
* other non-null string. A null input value will yield a null
* return value.
* @param s String
* @return Boolean or null
*/
@Override
public Boolean convertToEntityAttribute(String s) {
if (s == null) {
return null;
}
if (HAPPY.equals(s)) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}
}
NULL
tính cho NULL
giá trị cơ sở dữ liệu, câu trả lời này không cung cấp bất kỳ giá trị gia tăng nào cho câu trả lời @MarKG. Tốt nhất hãy nắm bắt sự khác biệt đó dưới dạng nhận xét.
Để thậm chí làm tốt hơn ánh xạ boolean tới Y / N, hãy thêm vào cấu hình ngủ đông của bạn:
<!-- when using type="yes_no" for booleans, the line below allow booleans in HQL expressions: -->
<property name="hibernate.query.substitutions">true 'Y', false 'N'</property>
Bây giờ bạn có thể sử dụng boolean trong HQL, ví dụ:
"FROM " + SomeDomainClass.class.getName() + " somedomainclass " +
"WHERE somedomainclass.someboolean = false"
Để làm điều đó theo cách JPA chung bằng cách sử dụng chú thích getter, ví dụ dưới đây phù hợp với tôi với Hibernate 3.5.4 và Oracle 11g. Lưu ý rằng getter và setter ( getOpenedYnString
và setOpenedYnString
) được ánh xạ là các phương thức riêng tư. Các phương thức đó cung cấp ánh xạ nhưng tất cả các truy cập có lập trình vào lớp đều sử dụng phương thức getOpenedYn
và setOpenedYn
.
private String openedYn;
@Transient
public Boolean getOpenedYn() {
return toBoolean(openedYn);
}
public void setOpenedYn(Boolean openedYn) {
setOpenedYnString(toYesNo(openedYn));
}
@Column(name = "OPENED_YN", length = 1)
private String getOpenedYnString() {
return openedYn;
}
private void setOpenedYnString(String openedYn) {
this.openedYn = openedYn;
}
Đây là lớp sử dụng với các phương thức tĩnh toYesNo
và toBoolean
:
public class JpaUtil {
private static final String NO = "N";
private static final String YES = "Y";
public static String toYesNo(Boolean value) {
if (value == null)
return null;
else if (value)
return YES;
else
return NO;
}
public static Boolean toBoolean(String yesNo) {
if (yesNo == null)
return null;
else if (YES.equals(yesNo))
return true;
else if (NO.equals(yesNo))
return false;
else
throw new RuntimeException("unexpected yes/no value:" + yesNo);
}
}
sử dụng bộ chuyển đổi JPA 2.1 là giải pháp tốt nhất, tuy nhiên nếu bạn đang sử dụng phiên bản JPA cũ hơn, tôi có thể đề xuất thêm một giải pháp (hoặc cách giải quyết khác). Tạo một enum có tên BooleanWrapper với 2 giá trị T và F và thêm phương thức sau vào nó để nhận giá trị được bao bọc public Boolean getValue() { return this == T; }
:, ánh xạ nó với @Enumerated (EnumType.STRING).