代码之家  ›  专栏  ›  技术社区  ›  Mykola Golubyev

将数据库第1列、第2列、第n列映射到元素集合

  •  2
  • Mykola Golubyev  · 技术社区  · 16 年前

    在旧的数据库表中,我们对列进行了编号,如c1、c2、c3、c100或m1、m2、m3、m100。
    此列表示blob数据。

    无法更改此数据库中的任何内容。

    通过使用JPA可嵌入,我们将所有列映射到单个字段。然后在嵌入期间,我们使用100个覆盖注释来覆盖名称。

    最近我们换了冬眠,我发现了 用户集合类型 复合用户类型 . 但是我没有发现任何与我的用例很接近的用例。

    是否可以通过使用Hibernate实现某些用户类型,以便将一组列映射到集合 无需额外查询 ?

    编辑:
    正如您可能注意到的,各个表的列名称可能不同。我想创建一个类似“legacyarray”的类型,不需要每次使用该类型时都指定所有@列。 但是我会用

      @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;
    
    6 回复  |  直到 16 年前
        1
  •  3
  •   Jack Leow    16 年前

    我可以想出几种方法来做到这一点。

    1.为模拟规范化表结构的集合信息创建视图,并将其作为集合映射到休眠状态:

    假设调用了现有表 primaryentity ,我将创建一个类似于以下内容的视图:

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

    现在从Hibernate的角度来看, childentity 只是一个规范化表,该表具有 primarykey . 映射应该是非常直接的,这里介绍:

    这种方法的好处是:

    • 从Hibernate的角度来看,表是规范化的,这是一个相当简单的映射
    • 没有对现有表的更新

    缺点:

    • 数据是只读的,我认为您的视图不能以可更新的方式定义(我可能错了)
    • 需要更改数据库,您可能需要创建大量视图

    或者,如果DBA甚至不允许您向数据库添加视图,或者您需要执行更新:


    2。使用Hibernate dynamic model mapping facility 将c1、c2、c3属性映射到 Map 还有一些代码 DAO 层在映射和集合属性之间进行适当的对话:

    我自己从来没有这样做过,但我相信Hibernate允许您将表映射到哈希映射。我不确定Hibernate是如何动态地允许您这样做的(即,您是否可以不必简单地指定表名,让Hibernate自动映射所有列?)但这是我能想到的另一种方法。

    如果采用这种方法,请务必使用 data access object 模式,并确保对客户端代码隐藏内部实现(使用哈希映射)。另外,在写入数据库之前,一定要检查集合的大小是否不超过可用列的数目。

    这种方法的好处是:

    • 完全不更改数据库
    • 数据可更新
    • O/R映射相对简单

    缺点:

    • 在DAO层中有很多管道可以映射适当的类型
    • 使用将来可能改变的实验性休眠功能
        2
  •  1
  •   duffymo    16 年前

    就我个人而言,我认为这个设计听起来像是断裂了 first normal form 对于关系数据库。如果需要C101或M101会发生什么?是否再次更改架构?我觉得这很有侵略性。

    如果你把冬眠加入到混合物中,情况会更糟。添加C101或M101意味着必须改变Java对象、Hibernate映射、一切。

    如果您与C和M表有1:M的关系,那么您可以通过添加其他行来处理我刚才引用的案例。Java对象包含集合& lt;c& gt;或集合& lt;m & gt;您的休眠映射是一对多的,不会更改。

    也许是因为你没有看到任何与你的案例相匹配的休眠例子,因为这是一个不推荐的设计。

    如果你必须的话,也许你应该看看 Hibernate Component Mapping .

    更新:这是遗产的事实被适当地指出。我提出的第一个正常形式的观点是,对于将来可能会发现这个问题的其他人来说,就像对于发布问题的人一样。我不想以这样一种方式回答这个问题:它默默地宣称这个设计是“好的”。

    指出Hibernate组件映射是相关的,因为在搜索时,知道要查找的内容的名称可能是关键。Hibernate允许对象模型比它映射的关系模型更细粒度。您可以自由地为非规范化模式建模(例如,将名称和地址对象作为较大的Person对象的一部分)。这就是他们给这种技术起的名字。它也可能有助于找到其他的例子。

        3
  •  1
  •   Kip    16 年前

    对不起,如果我误解了你的问题,我对冬眠不太了解。但是,您不能在从数据库中选择的过程中连接以获得您想要的东西吗?

    像:

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

    (当然,连接操作符在RDBMS之间是不同的。)

        4
  •  1
  •   Aaron Digulla    16 年前

    [编辑]我建议使用 CompositeUserType . Here is an example . 在“Hibernate Java持久化”一书的第228页中也有一个很好的例子。

    这允许您在Java中处理多个列作为单个对象。

    映射如下:

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

    在正常查询期间,Hibernate将一次加载所有列。

    在这种情况下,必须将int值从列表复制到 nullSafeSet . Pseudocode:

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

    nullSafeGet 当列为空时,必须创建列表并停止添加元素。为了增加安全性,我建议创建自己的列表实现,它不允许超过列数(继承自 ArrayList 超驰 ensureCapacity() )

    [edit2]如果不想键入所有@column注释,请为它们使用代码生成器。这可以像脚本一样简单,脚本提供一个名称和一个数字,然后它将@column(…)打印到system.out。脚本运行后,只需将数据剪切并粘贴到源中即可。

    唯一的其他解决方案是访问内部Hibernate API,在运行时构建该信息,但该API是内部的,因此很多东西都是私有的。可以使用Java反射和 setAccessible(true) 但这段代码在下一次Hibernate更新中可能无法生存。

        5
  •  0
  •   oxbow_lakes    16 年前

    你可以使用 UserType s将给定数量的列映射到所需的任何类型。如果(例如)集合的大小总是由已知数量的项限定,那么这可能是集合。

    我用冬眠已经有一段时间了(超过3年),所以我很生锈,但我记得这很容易做到;你的 BespokeUserType 类通过了 ResultSet 水合物 你的目标。

        6
  •  0
  •   Steven    16 年前

    我也从来没有用过冬眠。

    我建议用翻译语言编写一个小程序(例如 Python )在其中,可以像执行命令一样执行字符串。您可以构造一个语句,它将单调的工作从手工操作中去掉。