Чи можу я встановити JPA / hibernate для збереження Boolean
типів як Y/N
? У базі даних (стовпець визначається як varchar2(1)
. В даний час він зберігає їх як 0/1
. База даних - Oracle.
Відповіді:
Єдиний спосіб, як я зрозумів, як це зробити - це наявність двох властивостей для мого класу. Один як логічний для API програмування, який не включений у зіставлення. Це getter і setter посилаються на приватну змінну char, яка є Y / N. Потім у мене є ще одне захищене властивість, яке включено до зіставлення сплячого режиму, і воно отримує та встановлює посилання безпосередньо на змінну private char.
РЕДАГУВАТИ: Як уже зазначалося, є інші рішення, які безпосередньо вбудовані в Hibernate. Я залишаю цю відповідь, оскільки вона може працювати в ситуаціях, коли ви працюєте зі застарілим полем, яке не дуже добре грає із вбудованими опціями. Крім того, серйозних негативних наслідків у цього підходу немає.
Hibernate має вбудований тип "yes_no", який буде робити те, що ви хочете. Він відображається у стовпці CHAR (1) у базі даних.
Основне відображення: <property name="some_flag" type="yes_no"/>
Зіставлення анотацій (розширення Hibernate):
@Type(type="yes_no")
public boolean getFlag();
Це чистий 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
та випустити винятки, якщо вміст бази даних не є суворо правильним, то, я думаю, ви не повинні приймати будь-які символи, крім "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);
}
Y
, N
і T
. Я також не впевнений, що слід опустити випадок наявності нульового значення в результаті перетворення.
Я використав концепцію відповіді, опубліковану @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;
}
}
Цей варіант також цікавий, якщо ви любите смайлики і просто втомилися від Т / Н чи Т / Ж у вашій базі даних. У цьому випадку стовпець бази даних повинен містити два символи замість одного. Можливо, це не велика проблема.
/**
* 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
властивості для NULL
значення бази даних, ця відповідь не надає жодної доданої вартості за допомогою відповіді @MarKG. Найкраще цю різницю фіксувати як коментар.
Щоб навіть краще виконати булеве відображення до 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>
Тепер ви можете використовувати логічні значення в HQL, наприклад:
"FROM " + SomeDomainClass.class.getName() + " somedomainclass " +
"WHERE somedomainclass.someboolean = false"
Щоб зробити це загальним способом JPA, використовуючи анотації getter, наведений нижче приклад працює для мене з Hibernate 3.5.4 та Oracle 11g. Зверніть увагу, що зіставлений getter та setter ( getOpenedYnString
і setOpenedYnString
) є приватними методами. Ці методи забезпечують відображення, але весь програмний доступ до класу використовує методи getOpenedYn
and 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);
}
}
використання перетворювачів JPA 2.1 - найкраще рішення, однак, якщо ви використовуєте попередню версію JPA, я можу порекомендувати ще одне рішення (або обхідний шлях). Створіть перерахування під назвою BooleanWrapper з 2 значеннями T і F і додайте до нього наступний метод, щоб отримати загорнуте значення:, public Boolean getValue() { return this == T; }
зіставити його з @Enumerated (EnumType.STRING).