Java 配置休眠(使用 JPA)以存储类型 Boolean 而不是 0/1 的 Y/N

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1154833/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:19:01  来源:igfitidea点击:

Configure hibernate (using JPA) to store Y/N for type Boolean instead of 0/1

javahibernatejpa

提问by sengs

Can I setup JPA/hibernate to persist Booleantypes as Y/N? In the database (the column is defined as varchar2(1). It currently stores them as 0/1. The database is Oracle.

我可以设置 JPA/hibernate 将Boolean类型持久化为Y/N吗?在数据库中(列被定义为varchar2(1)。它目前将它们存储为0/1。数据库是 Oracle。

采纳答案by Spencer Ruport

The only way I've figured out how to do this is to have two properties for my class. One as the boolean for the programming API which is not included in the mapping. It's getter and setter reference a private char variable which is Y/N. I then have another protected property which is included in the hibernate mapping and it's getters and setters reference the private char variable directly.

我想出如何做到这一点的唯一方法是为我的班级设置两个属性。一个作为未包含在映射中的编程 API 的布尔值。它的 getter 和 setter 引用了一个私有的 char 变量,它是 Y/N。然后我有另一个受保护的属性,它包含在休眠映射中,它的 getter 和 setter 直接引用私有 char 变量。

EDIT: As has been pointed out there are other solutions that are directly built into Hibernate. I'm leaving this answer because it can work in situations where you're working with a legacy field that doesn't play nice with the built in options. On top of that there are no serious negative consequences to this approach.

编辑:正如已经指出的那样,还有其他直接内置到 Hibernate 中的解决方案。我离开这个答案是因为它可以在您使用与内置选项不兼容的遗留字段的情况下工作。最重要的是,这种方法没有严重的负面影响。

回答by ChssPly76

Hibernate has a built-in "yes_no" type that would do what you want. It maps to a CHAR(1) column in the database.

Hibernate 有一个内置的“yes_no”类型,可以做你想做的事。它映射到数据库中的 CHAR(1) 列。

Basic mapping: <property name="some_flag" type="yes_no"/>

基本映射: <property name="some_flag" type="yes_no"/>

Annotation mapping (Hibernate extensions):

注解映射(Hibernate 扩展):

@Type(type="yes_no")
public boolean getFlag();

回答by M.A. Hogendoorn

To even do better boolean mapping to Y/N, add to your hibernate configuration:

为了更好地映射到 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>

Now you can use booleans in HQL, for example:

现在您可以在 HQL 中使用布尔值,例如:

"FROM " + SomeDomainClass.class.getName() + " somedomainclass " +
"WHERE somedomainclass.someboolean = false"

回答by Dave Moten

To do it in a generic JPA way using getter annotations, the example below works for me with Hibernate 3.5.4 and Oracle 11g. Note that the mapped getter and setter (getOpenedYnStringand setOpenedYnString) are private methods. Those methods provide the mapping but all programmatic access to the class is using the getOpenedYnand setOpenedYnmethods.

要使用 getter 注释以通用 JPA 方式执行此操作,以下示例适用于 Hibernate 3.5.4 和 Oracle 11g。请注意,映射的 getter 和 setter(getOpenedYnStringsetOpenedYnString)是私有方法。这些方法提供映射,但对类的所有编程访问都使用getOpenedYnsetOpenedYn方法。

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;
}

Here's the util class with static methods toYesNoand toBoolean:

这是带有静态方法的 util 类toYesNotoBoolean

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);
    }
}

回答by MarcG

This is pure JPA without using getters/setters. As of 2013/2014 it is the best answer without using any Hibernate specific annotations, but please note this solution is JPA 2.1, and was not available when the question was first asked:

这是不使用 getter/setter 的纯 JPA。截至 2013/2014 年,这是不使用任何 Hibernate 特定注释的最佳答案,但请注意,此解决方案是 JPA 2.1,在首次提出问题时不可用:

@Entity
public class Person {    

    @Convert(converter=BooleanToStringConverter.class)
    private Boolean isAlive;    
    ...
}

And then:

进而:

@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);
        }
    }

Edit:

编辑:

The implementation above considers anything different from character "Y", including null, as false. Is that correct? Some people here consider this incorrect, and believe that nullin the database should be nullin Java.

上面的实现考虑了与字符“Y”不同的任何东西,包括null, as false。那是对的吗?这里有些人认为这是不正确的,并认为null在数据库中应该是nullJava。

But if you return nullin Java, it will give you a NullPointerExceptionif your field is a primitive boolean. In other words, unless some of your fields actually use the class Booleanit's best to consider nullas false, and use the above implementation. Then Hibernate will not to emit any exceptions regardless of the contents of the database.

但是如果你null用 Java返回,它会给你一个NullPointerExceptionif 你的字段是一个原始的 boolean。换句话说,除非你的一些领域的实际使用类布尔也最好考虑nullfalse,并使用上述实现。无论数据库的内容如何,​​Hibernate 都不会发出任何异常。

And if you do want to accept nulland emit exceptions if the contents of the database are not strictly correct, then I guess you should not accept anycharacters apart from "Y", "N" and null. Make it consistent, and don't accept any variations like "y", "n", "0" and "1", which will only make your life harder later. This is a more strict implementation:

而如果你想接受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);
    }

And yet another option, if you want to allow for nullin Java but not in the database:

还有另一种选择,如果你想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);
    }

回答by Ravshan Samandarov

using JPA 2.1 converters is the best solution, however if you are using earlier version of JPA I can recommend one more solution (or workaround). Create an enum called BooleanWrapper with 2 values of T and F and add following method to it to get wrapped value: public Boolean getValue() { return this == T; }, map it with @Enumerated(EnumType.STRING).

使用 JPA 2.1 转换器是最好的解决方案,但是如果您使用的是早期版本的 JPA,我可以推荐另一种解决方案(或解决方法)。创建一个名为 BooleanWrapper 的枚举,具有 2 个 T 和 F 值,并向其添加以下方法以获取包装值:public Boolean getValue() { return this == T; },将其映射为 @Enumerated(EnumType.STRING)。

回答by Jim Tough

I used the concept from the answer posted by @marcg and it works great with JPA 2.1. His code wasn't quite right, so I'm posted my working implementation. This will convert Booleanentity fields to a Y/N character column in the database.

我使用了@marcg 发布的答案中的概念,它适用于 JPA 2.1。他的代码不太正确,所以我发布了我的工作实现。这会将Boolean实体字段转换为数据库中的 Y/N 字符列。

From my entity class:

从我的实体类:

@Convert(converter=BooleanToYNStringConverter.class)
@Column(name="LOADED", length=1)
private Boolean isLoadedSuccessfully;

My converter class:

我的转换器类:

/**
 * 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;
    }

}

This variant is also fun if you love emoticons and are just sick and tired of Y/N or T/F in your database. In this case, your database column must be two characters instead of one. Probably not a big deal.

如果您喜欢表情符号并且只是厌倦了数据库中的 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;
    }

}