Можно ли настроить JPA/hibernate для сохранения типов Boolean
как Y/N
? В базе данных (столбец определяется как varchar2(1)
. В настоящее время он хранит их как 0/1
. База данных - это Oracle.
Настройте hibernate (используя JPA) для хранения Y/N для типа Boolean вместо 0/1
Ответ 1
Единственный способ, которым я понял, как это сделать - это иметь два свойства для моего класса. Один как логическое значение для API программирования, который не включен в отображение. Это getter и setter ссылаются на частную переменную char, которая является Y/N. Затем у меня есть другое защищенное свойство, которое включено в отображение hibernate, и его методы получения и установки напрямую ссылаются на частную переменную char.
РЕДАКТИРОВАТЬ: Как уже было отмечено, есть другие решения, которые непосредственно встроены в Hibernate. Я оставляю этот ответ, потому что он может работать в ситуациях, когда вы работаете с устаревшим полем, которое не очень хорошо сочетается со встроенными опциями. Кроме того, нет серьезных негативных последствий для этого подхода.
Ответ 2
Hibernate имеет встроенный тип yes_no, который будет делать то, что вы хотите. Он сопоставляется столбцу CHAR (1) в базе данных.
Базовое сопоставление: <property name="some_flag" type="yes_no"/>
Отображение аннотаций (расширения Hibernate):
@Type(type="yes_no")
public boolean getFlag();
Ответ 3
Это чистый JPA без использования геттеров/сеттеров. Начиная с 2013/2014 года это лучший ответ без использования каких-либо аннотаций Hibernate, но обратите внимание, что это решение является JPA 2.1, и не было доступно, когда вопрос был задан первым:
@Entity
public class Person {
@Convert(converter=BooleanToStringConverter.class)
private Boolean isAlive;
...
}
И затем:
@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);
}
}
Изменить:
В приведенной выше реализации рассматривается нечто иное, чем символ "Y", включая null
, как false
. Это верно? Некоторые люди считают это неправильным и считают, что null
в базе данных должно быть null
в Java.
Но если вы вернете null
в Java, он даст вам NullPointerException
, если ваше поле является примитивным логическим. Другими словами, если только некоторые из ваших полей не используют класс Boolean, лучше рассмотреть null
как false
и использовать приведенную выше реализацию. Тогда Hibernate не будет выдавать никаких исключений, независимо от содержимого базы данных.
И если вы хотите принять null
и испускать исключения, если содержимое базы данных не является строго правильным, то я думаю, вы не должны принимать символы any, кроме "Y", N "и null
. Сделайте его согласованным и не принимайте никаких изменений, таких как" y "," n "," 0 "и" 1", что только усложнит вашу жизнь позже. Это более строгая реализация:
@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);
}
И еще один вариант, если вы хотите разрешить null
в Java, но не в базе данных:
@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);
}
Ответ 4
Я использовал концепцию из ответа, отправленного @marcg, и он отлично работает с JPA 2.1. Его код был не совсем прав, поэтому я опубликовал свою рабочую реализацию. Это преобразует поля объекта Boolean
в столбец символов Y/N в базе данных.
Из класса сущности:
@Convert(converter=BooleanToYNStringConverter.class)
@Column(name="LOADED", length=1)
private Boolean isLoadedSuccessfully;
Мой класс преобразователя:
/**
* 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;
}
}
Этот вариант также забавна, если вы любите смайлики и просто устали от Y/N или T/F в своей базе данных. В этом случае столбец базы данных должен содержать два символа вместо одного. Наверное, это не большая проблема.
/**
* 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;
}
}
Ответ 5
Чтобы сделать более хорошее булево отображение в Y/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>
Теперь вы можете использовать booleans в HQL, например:
"FROM " + SomeDomainClass.class.getName() + " somedomainclass " +
"WHERE somedomainclass.someboolean = false"
Ответ 6
Чтобы сделать это с помощью общего метода JPA, используя аннотации геттера, приведенный ниже пример работает для меня с Hibernate 3.5.4 и Oracle 11g. Обратите внимание, что отображаемые геттер и сеттер (getOpenedYnString
и setOpenedYnString
) являются частными методами. Эти методы обеспечивают отображение, но весь программный доступ к классу использует методы getOpenedYn
и 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;
}
Здесь класс util со статическими методами toYesNo
и 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);
}
}
Ответ 7
использование конвертеров JPA 2.1 - лучшее решение, однако, если вы используете более раннюю версию JPA, я могу порекомендовать еще одно решение (или обходное решение). Создайте перечисление с именем BooleanWrapper с 2 значениями T и F и добавьте следующий метод к нему, чтобы получить завернутое значение: public Boolean getValue() { return this == T; }
, сопоставьте его с @Enumerated (EnumType.STRING).