Pregunta

En las tablas de bases de datos heredadas tenemos columnas numeradas como C1, C2, C3, C100 o M1, M2, M3, M100.
Estas columnas representan datos BLOB.

No es posible cambiar nada en esta base de datos.

Al utilizar JPA Embeddable, asignamos todas las columnas a campos individuales.Y luego, durante la incrustación, anulamos los nombres mediante el uso de 100 anotaciones de anulación.

Recientemente cambiamos a Hibernar y encontré cosas como Tipo de colección de usuarios y Tipo de usuario compuesto.Pero no encontré ningún caso de uso cercano al mío.

¿Es posible implementar algún tipo de usuario mediante Hibernate para poder asignar un conjunto de columnas a una colección? sin consultas adicionales?

Editar:
Como probablemente habrás notado, los nombres de las columnas pueden diferir de una tabla a otra.Quiero crear un tipo como "LegacyArray" sin necesidad de especificar todas las @Columns cada vez que uso este tipo.Pero en lugar de eso usaría

  @Type(type = "LegacyArrayUserType",
        parameters =
   {
      @Parameter(name = "prefix", value = "A"),
      @Parameter(name = "size", value = "128")
   })
   List<Integer> legacyA;

  @Type(type = "LegacyArrayUserType",
        parameters =
   {
      @Parameter(name = "prefix", value = "B"),
      @Parameter(name = "size", value = "64")
   })
   List<Integer> legacyB;
¿Fue útil?

Solución

Se me ocurren un par de formas en las que haría esto.

1.Cree vistas para la información de la colección que simule una estructura de tabla normalizada y asígnela a Hibernate como una colección:

Suponiendo que su tabla existente se llame primaryentity, crearía una vista similar a la siguiente:

-- untested SQL...
create view childentity as
(select primaryentity_id, c1 from primaryentity union
select primaryentity_id, c2 from primaryentity union
select primaryentity_id, c3 from primaryentity union
--...
select primaryentity_id, c100 from primaryentity)

Ahora desde la perspectiva de Hibernate, childentity es solo una tabla normalizada que tiene una clave externa para primarykey.Mapear esto debería ser bastante sencillo y se trata aquí:

Los beneficios de este enfoque:

  • Desde el punto de vista de Hibernate, las tablas están normalizadas, es un mapeo bastante simple.
  • No hay actualizaciones para sus tablas existentes

Los inconvenientes:

  • Los datos son de solo lectura, no creo que su vista pueda definirse de manera actualizable (podría estar equivocado)
  • Requiere cambios en la base de datos, es posible que necesite crear muchas vistas

Alternativamente, si su DBA ni siquiera le permite agregar una vista a la base de datos, o si necesita realizar actualizaciones:


2.Utilice Hibernate función de mapeo de modelos dinámicos para asignar sus propiedades C1, C2, C3 a un Mapa, y tener algún código que tu DAO La capa realiza la conversación adecuada entre el Mapa y la propiedad Colección:

Nunca he hecho esto yo mismo, pero creo que Hibernate te permite asignar tablas a HashMaps.No estoy seguro de qué tan dinámicamente Hibernate le permite hacer esto (es decir, ¿puede simplemente especificar el nombre de la tabla y hacer que Hibernate asigne automáticamente todas las columnas?), pero es otra forma en que puedo pensar en hacer esto.

Sin embargo, si opta por este enfoque, asegúrese de utilizar el objeto de acceso a datos patrón y asegúrese de que la implementación interna (uso de HashMaps) esté oculta del código del cliente.También asegúrese de verificar antes de escribir en la base de datos que el tamaño de su colección no exceda la cantidad de columnas disponibles.

Los beneficios de este enfoque:

  • Ningún cambio en la base de datos en absoluto
  • Los datos son actualizables.
  • El mapeo O/R es relativamente simple

Los inconvenientes:

  • Mucha plomería en la capa DAO para mapear los tipos apropiados
  • Utiliza funciones experimentales de Hibernación que pueden cambiar en el futuro.

Otros consejos

En lo personal, creo que el diseño suena como que rompe primera forma normal para bases de datos relacionales. ¿Qué pasa si necesita C101 o M101? Cambiar el esquema de nuevo? Creo que es muy intrusivo.

Si se agrega a la mezcla Hibernate es aún peor. Añadiendo C101 o M101 significa tener que alterar sus objetos de Java, las asignaciones de Hibernate, todo.

Si usted tiene 1: relaciones m con cuadros C y M, que sería capaz de manejar los casos que acabo de citar añadiendo más filas. Sus objetos de Java contiene la colección o colección . Las asignaciones de Hibernate son uno-a-muchos que no cambian.

Tal vez la razón por la que aún no hay ejemplos de Hibernate para que coincida con su caso porque se trata de un diseño que no es recomendable.

Si es necesario, puede que usted debe buscar en Hibernate Mapeo de componentes .

ACTUALIZACIÓN: El hecho de que este es el legado se tomó debida nota. Mi punto en la educación de la primera forma normal es tanto para otros que podrían encontrar esta pregunta en el futuro como lo es para la persona que envió la pregunta. No me gustaría que para responder a la pregunta de una manera tal que en silencio afirmó este diseño como "buena".

Tras señalar mapeo componente Hibernate es pertinente, ya que conocer el nombre de lo que estás buscando puede ser la clave cuando usted está buscando. Hibernate permite un modelo de objetos a ser de grano más fino que el modelo relacional se asigna. Usted es libre para modelar un esquema sin normalizar (por ejemplo, nombre y dirección objetos como parte de un objeto persona mayor). Eso es sólo el nombre que dan dicha técnica. Podría ayudar a encontrar otros ejemplos.

Lo siento si estoy malentendido aquí su problema, no sé mucho acerca de hibernación. Pero no se puede simplemente concatenar durante la selección de la base de datos para obtener algo así como lo que quieres?

Al igual que:

SELECT whatever
     , C1||C2||C3||C4||...||C100 AS CDATA
     , M1||M2||M3||M4||...||M100 AS MDATA
FROM ...
WHERE ...

(Por supuesto, el operador de concatenación difiere entre los RDBMS).

[EDIT] Es mejor utilizar un CompositeUserType. Este es un ejemplo . También hay un buen ejemplo de la página 228f en el libro "La persistencia de Java con Hibernate".

Esto le permite manejar las tantas columnas como un solo objeto en Java.

El mapeo es el siguiente:

@org.hibernate.annotations.Columns(columns = {
    @Column(name="C1"),
    @Column(name="C2"),
    @Column(name="C3"),
    ...
})
private List<Integer> c;

Hibernate los carga todas las columnas a la vez durante la consulta normal.

En su caso, debe copiar los valores int de la lista en un número fijo de columnas en nullSafeSet. Pseudocódigo:

for (int i=1; i<numColumns; i++)
    if (i < list.size())
        resultSet.setInt(index+i, list.get(i));
    else
        resultSet.setNull(index+i, Hibernate.INTEGER.sqlType());

En nullSafeGet debe crear una lista y dejar de añadir elementos a la hora de una columna es NULL. Para mayor seguridad, le sugiero a crear su propia implementación de la lista que no permite que crezca más allá del número de columnas (heredar de ArrayList y ensureCapacity() anulación).

[Edit2] Si no desea escribir todas las anotaciones @column, utilice un generador de código para ellos. Esto puede ser tan simple como script que le da un nombre y un número y se imprime @Column (...) en System.out. Después de que el guión corrió, acaba de cortar y pegar los datos en la fuente.

La única otra solución sería acceder a la API de Hibernate interna para construir esa información en tiempo de ejecución, sino que API es interna, por lo que una gran cantidad de material es privado. Puede utilizar la reflexión Java y setAccessible(true) pero ese código probablemente no va a sobrevivir a la próxima actualización de hibernación.

Puede utilizar UserTypes para asignar un número determinado de columnas de cualquier tipo que se desea. Esto podría ser una colección si (por ejemplo) para las colecciones son siempre limitado en tamaño por un número conocido de artículos.

Ha sido un tiempo (> 3 años) desde que utiliza Hibernate así que estoy bastante oxidado pero recuerdo que sea muy fácil de hacer; la clase BespokeUserType se pasa el ResultSet a hidrato el objeto de la misma.

También yo nunca he usado Hibernate.

Le sugiero escribir un pequeño programa en un lenguaje interpretado (como Python ) en el que se puede ejecutar una cadena como si se tratara de un comando. Se podría construir una instrucción que se lleva a cabo el trabajo tedioso de hacer lo que quiere hacer manualmente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top