【问题标题】:Configure hibernate (using JPA) to store Y/N for type Boolean instead of 0/1配置休眠(使用 JPA)以存储布尔类型的 Y/N 而不是 0/1
【发布时间】:2010-11-12 09:27:36
【问题描述】:

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

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

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

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

    注解映射(Hibernate 扩展):

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

    【讨论】:

    • 对于那些感兴趣的人,还有一个“true_false”类型将存储“T”或“F”。
    • 这行得通,但我不能使用它,因为它是一个休眠特定的注释。感谢您的回答。可能会在不同的项目中使用它。
    • 这是针对 hibernate 4 和更高版本的,这意味着针对 java 1.6 和更高版本。不适用于休眠 3.*
    • @storm_buster Hibernate 4 在给出这个答案时不存在。它与 Hibernate 3.x 和 java 1.5 完美配合
    • 那么0或1怎么放呢?
    【解决方案2】:

    这是纯 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);
            }
        }
    

    编辑:

    上面的实现将任何与字符“Y”不同的东西(包括null)视为false。那是对的吗?这里有人认为这是不正确的,认为数据库中的null在Java中应该是null

    但如果你在 Java 中返回 null,如果你的字段是 原始布尔值,它会给你一个 NullPointerException。换句话说,除非您的某些字段实际上使用 class 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);
        }
    

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

    【讨论】:

    • 转换器显示了这个想法,但当然不起作用。转换器使用YNT 的可能值。我也不确定是否应该忽略由于转换而产生空值的情况。
    • @Matthias 是的,T 是一个错字。我修好了它。谢谢。
    • 我在使用 JPQL 的 Y/N 字段时遇到问题,并在此处发布了后续问题:stackoverflow.com/questions/39581225/…
    【解决方案3】:

    我使用了@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;
        }
    
    }
    

    【讨论】:

    • 是否需要拆箱'b.booleanValue()'?
    • 除了NULL 数据库值的NULL 属性外,此答案不提供任何超过@MarKG 答案的附加值。最好将这种差异记录为评论。
    • 你来晚了5年
    【解决方案4】:

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

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

    【讨论】:

    • 我不得不做一些类似的事情 - 我将成员的类型从 Boolean 更改为 String。在 getter 和 setter(获取并设置 Boolean)中,我编写了将 Y/N 转换为相应的布尔值的代码。
    • @bernardn 不,这样更好。
    【解决方案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>
    

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

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

    【讨论】:

    • 这是全球性的。不适用于单一属性。
    【解决方案6】:

    要使用 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;
    }
    

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-09
      • 1970-01-01
      • 2014-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多