¿Puedo configurar JPA / hibernate para persistir Boolean
tipos como Y/N
? En la base de datos (la columna se define como varchar2(1)
. Actualmente los almacena como 0/1
. La base de datos es Oracle.
80
La única forma en que he descubierto cómo hacer esto es tener dos propiedades para mi clase. Uno como booleano para la API de programación que no está incluido en el mapeo. Es getter y setter hacen referencia a una variable char privada que es Y / N. Luego tengo otra propiedad protegida que está incluida en el mapeo de hibernación y sus captadores y definidores hacen referencia a la variable char privada directamente.
EDITAR: Como se ha señalado, hay otras soluciones que están integradas directamente en Hibernate. Dejo esta respuesta porque puede funcionar en situaciones en las que está trabajando con un campo heredado que no funciona bien con las opciones integradas. Además de eso, este enfoque no tiene consecuencias negativas graves.
Hibernate tiene un tipo "yes_no" incorporado que haría lo que quieras. Se asigna a una columna CHAR (1) en la base de datos.
Mapeo básico:
<property name="some_flag" type="yes_no"/>
Mapeo de anotaciones (extensiones de Hibernate):
@Type(type="yes_no") public boolean getFlag();
fuente
Esto es JPA puro sin usar getters / setters. A partir de 2013/2014, es la mejor respuesta sin utilizar anotaciones específicas de Hibernate, pero tenga en cuenta que esta solución es JPA 2.1 y no estaba disponible cuando se hizo la pregunta por primera vez:
@Entity public class Person { @Convert(converter=BooleanToStringConverter.class) private Boolean isAlive; ... }
Y entonces:
@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); } }
Editar:
La implementación anterior considera cualquier cosa diferente del carácter "Y", incluyendo
null
, comofalse
. ¿Es eso correcto? Algunas personas aquí consideran que esto es incorrecto y creen quenull
la base de datos debería estarnull
en Java.Pero si regresa
null
en Java, le dará unNullPointerException
si su campo es un booleano primitivo . En otras palabras, a menos que algunos de sus campos realmente usen la clase Boolean , es mejor considerarnull
comofalse
y usar la implementación anterior. Entonces, Hibernate no emitirá ninguna excepción independientemente del contenido de la base de datos.Y si desea aceptar
null
y emitir excepciones si el contenido de la base de datos no es estrictamente correcto, supongo que no debe aceptar ningún carácter aparte de "Y", "N" ynull
. Hágalo coherente y no acepte variaciones como "y", "n", "0" y "1", que solo harán su vida más difícil más adelante. Esta es una implementación más estricta:@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); }
Y otra opción más, si desea permitirlo
null
en Java pero no en la base de datos:@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); }
fuente
Y
,N
yT
. Tampoco estoy seguro de que se deba omitir el caso de tener un valor nulo como resultado de una conversión.Usé el concepto de la respuesta publicada por @marcg y funciona muy bien con JPA 2.1. Su código no era del todo correcto, así que publiqué mi implementación de trabajo. Esto convertirá los
Boolean
campos de la entidad en una columna de caracteres Y / N en la base de datos.De mi clase de entidad:
@Convert(converter=BooleanToYNStringConverter.class) @Column(name="LOADED", length=1) private Boolean isLoadedSuccessfully;
Mi clase de convertidor:
/** * 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; } }
Esta variante también es divertida si te encantan los emoticonos y estás cansado de Y / N o T / F en tu base de datos. En este caso, la columna de su base de datos debe tener dos caracteres en lugar de uno. Probablemente no sea gran cosa.
/** * 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; } }
fuente
NULL
propiedad para elNULL
valor de la base de datos, esta respuesta no proporciona ningún valor agregado sobre la respuesta de @MarKG. Lo mejor es capturar esa diferencia como comentario.Para incluso hacer un mejor mapeo booleano a Y / N, agregue a su configuración de hibernació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>
Ahora puede usar booleanos en HQL, por ejemplo:
"FROM " + SomeDomainClass.class.getName() + " somedomainclass " + "WHERE somedomainclass.someboolean = false"
fuente
Para hacerlo de una manera JPA genérica usando anotaciones getter, el siguiente ejemplo me funciona con Hibernate 3.5.4 y Oracle 11g. Tenga en cuenta que el captador y el definidor mapeados (
getOpenedYnString
ysetOpenedYnString
) son métodos privados. Esos métodos proporcionan el mapeo, pero todo el acceso programático a la clase usa los métodosgetOpenedYn
ysetOpenedYn
.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; }
Aquí está la clase util con métodos estáticos
toYesNo
ytoBoolean
: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); } }
fuente
usar convertidores JPA 2.1 es la mejor solución, sin embargo, si está usando una versión anterior de JPA, puedo recomendar una solución más (o una solución alternativa). Cree una enumeración llamada BooleanWrapper con 2 valores de T y F y agregue el siguiente método para obtener el valor envuelto:,
public Boolean getValue() { return this == T; }
mapee con @Enumerated (EnumType.STRING).fuente