[java] 0/1 대신 부울 유형에 대해 Y / N을 저장하도록 최대 절전 모드 (JPA 사용)를 구성합니다.

Boolean유형 을 유지하도록 JPA / 최대 절전 모드를 설정할 수 있습니까 Y/N? 데이터베이스에서 (열은로 정의되어 varchar2(1)있습니다. 현재로 저장됩니다 0/1. 데이터베이스는 Oracle입니다.



답변

이 작업을 수행하는 방법을 알아 낸 유일한 방법은 클래스에 대해 두 가지 속성을 갖는 것입니다. 하나는 매핑에 포함되지 않은 프로그래밍 API의 부울입니다. getter와 setter는 Y / N 인 private char 변수를 참조합니다. 그런 다음 최대 절전 모드 매핑에 포함 된 또 다른 보호 속성이 있으며 getter 및 setter는 private char 변수를 직접 참조합니다.

편집 : 지적했듯이 Hibernate에 직접 내장 된 다른 솔루션이 있습니다. 이 대답은 기본 제공 옵션으로 잘 작동하지 않는 레거시 필드로 작업하는 상황에서 작동 할 수 있기 때문에이 답변을 남겨 둡니다. 또한이 접근 방식에는 심각한 부정적인 결과가 없습니다.


답변

Hibernate는 당신이 원하는 것을 할 수있는 “yes_no”타입을 내장하고 있습니다. 데이터베이스의 CHAR (1) 열에 매핑됩니다.

기본 매핑 : <property name="some_flag" type="yes_no"/>

주석 매핑 (Hibernate 확장) :

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


답변

이것은 getter / setter를 사용하지 않는 순수한 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에 자바가 있어야 한다고 생각합니다 .

그러나 nullJava로 반환 NullPointerException하면 필드가 기본 부울 인 경우 제공됩니다 . 즉, 귀하의 필드의 일부가 실제로 사용하지 않는 클래스를 부울 이 고려하는 것이 최선의 방법 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);
    }


답변

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

}


답변

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"


답변

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

여기에 정적 메서드와 폴더의 유틸리티 클래스의 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를 사용하는 경우 하나 이상의 솔루션 (또는 해결 방법)을 권장 할 수 있습니다. T와 F의 2 개 값이있는 BooleanWrapper라는 열거 형을 만들고 여기에 다음 메서드를 추가하여 래핑 된 값을 가져옵니다. public Boolean getValue() { return this == T; }, @Enumerated (EnumType.STRING)로 매핑합니다.