我可以设置JPA / hibernate以将Boolean
类型保留为Y/N
吗?在数据库中(该列定义为varchar2(1)
。它当前将它们存储为0/1
。数据库是Oracle。
答案 0 :(得分:135)
Hibernate有一个内置的“yes_no”类型,可以做你想要的。它映射到数据库中的CHAR(1)列。
基本映射:<property name="some_flag" type="yes_no"/>
注释映射(Hibernate扩展):
@Type(type="yes_no")
public boolean getFlag();
答案 1 :(得分:77)
这是纯粹的JPA而不使用getter / setter。截至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);
}
}
修改:
上述实现会将与字符&#34; Y&#34;(包括null
)不同的任何内容视为false
。那是对的吗?这里的一些人认为这是不正确的,并且认为数据库中的null
应该是Java中的null
。
但是如果你在Java中返回null
,如果你的字段是原始布尔值,它会给你一个NullPointerException
。换句话说,除非您的某些字段实际使用类布尔,否则最好将null
视为false
,并使用上述实现。然后,无论数据库的内容如何,Hibernate都不会发出任何异常。
如果您确实想要接受null
并在数据库内容严格不正确的情况下发出异常,那么我猜你不应该接受任何字符而不是&#34 ; Y&#34;,&#34; N&#34;和null
。使其保持一致,并且不接受任何变体,例如&#34; y&#34;,&#34; n&#34;,&#34; 0&#34;和&#34; 1&#34;,这只会让你的生活更加艰难。这是一个更严格的实施:
@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);
}
还有另一种选择,如果你想在Java中允许null
但在数据库中不允许:
@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);
}
答案 2 :(得分:12)
我使用了@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;
}
}
答案 3 :(得分:8)
我弄清楚如何做到这一点的唯一方法是为我的班级提供两个属性。一个作为编程API的布尔值,未包含在映射中。它是getter和setter引用的私有char变量,它是Y / N.然后我有另一个受保护的属性,它包含在hibernate映射中,它的getter和setter直接引用私有char变量。
答案 4 :(得分:2)
要做更好的布尔映射到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"
答案 5 :(得分:0)
要使用getter注释以通用JPA方式执行此操作,下面的示例适用于Hibernate 3.5.4和Oracle 11g。请注意,映射的getter和setter(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;
}
这是包含静态方法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);
}
}
答案 6 :(得分:0)
使用JPA 2.1转换器是最好的解决方案,但是如果您使用的是早期版本的JPA,我可以推荐另外一个解决方案(或解决方法)。创建一个名为BooleanWrapper的枚举,其中包含2个T和F值,并向其添加以下方法以获取包装值:public Boolean getValue() { return this == T; }
,使用@Enumerated(EnumType.STRING)映射它。