【问题标题】:Hibernate Lookup tables: As an Object Relation or as a code/keyHibernate 查找表:作为对象关系或作为代码/键
【发布时间】:2011-11-18 19:34:28
【问题描述】:

所以,我正在开发一个包含大量关系和查找表的应用程序,但这一切都归结为:

人物

id INT (PK)
... (name, address, etc)
optcode VARCHAR (FK to Options)
typecode VARCHAR (FK to Types)

选项

optcode VARCHAR (PK)
optdesc VARCHAR
... (more meta data, like date added, etc)

类型

code VARCHAR (PK)
desc VARCHAR
... (more meta data, like date added, etc)

我正在使用 hibernate 来访问这些表,一方面,对象关系有好处,但另一方面,仅使用字符串作为代码效果更好。

Object Relations 与 Keys 相比两者哪个更好?

只使用键:

public class Person {
     private int id;
     ... (more attributes)
     private String optcode;
     private String typecode;
}
In the services:
Person person = new Person();
person.setOptcode("ABC");
person.setTypecode("XYZ");
session.save(person);

或者O/R方式:

public class Person {
     private int id;
     ... (more attributes)
     @JoinColumn
     private Options option;
     @JoinColumn
     private Types type;
}
In the services:
Person person = new Person();
person.setOption(new Options("ABC")); //Assume constructor fills in the 'optcode'
person.setType(new Types("XYZ"));     //Same, with 'code'
session.save(person);

在大多数持久性情况下,我只有“代码”,但很多时候在显示数据时显示“描述”会很好

因为我将有一个地方来管理 Options 和 Types 实体,所以它们无论如何都会存在,但是必须将“代码”包装在一个对象中是很烦人的。

您认为不同方式的优缺点是什么?如果我只是将两者都放入 Person 对象中,这样我就可以使用更方便的方法了怎么办?让 setter 将字符串推入新的 Options/Types 实体怎么样?

我正在尝试确定最好的方法,以便它可以保持一致,现在我一直在做需要最少数量的新实体的任何事情,但最终一切都将由休眠实体表示。

更新: Person Entity 最终将拥有近 20 个唯一的实体关系(每个都指向不同的表),web-ui 可能会有包含每个值的下拉列表表,所以我希望我只有用于持久性的“代码”。 相关:我实际上使用的是 PersonImpl(普通 POJO)和 PersonEntity(Hibernate 实体)和 Dozer Mapping。

【问题讨论】:

    标签: java database hibernate orm lookup-tables


    【解决方案1】:

    我遇到了这个问题,因为我想知道人们在遇到需要查找其他实体的实体后在做什么。这样做的主要问题是,您不能再仅仅创建一个实例,即使在测试中也是如此。我的首选方法是迁移到工厂或外部(例如非静态类)构建器。

    我对这个整体的问题是它非常基本,并且涉及很多容易出错的样板。例如,假设我有一个名为 Listing 的内容,我必须跟踪它的来源(我找到它的地方)。源是一个非常简单的实体,但现在我在列表中引用了它,如果不查找源然后注入适当的源,我将无法再创建列表。

    如果可能的话,通过简单的注释来处理这个是有意义的,例如类似于 mappedBy,但引用 id 或 name,然后容器可以进行查找和注入。

    但我们怀疑我们很快就会看到这一点..

    【讨论】:

      【解决方案2】:

      我想我只会使用 Hibernate 的 @MappedSuperclass 来处理表具有很多相同结构(“代码”、“描述”等)的情况,这样我就可以减少代码行数。但除此之外,O/R 似乎是要走的路。

      【讨论】:

      • 欢迎来到 Stack Overflow!如果您有新问题,请点击 按钮提出问题。如果您有足够的声誉,you may upvote 的问题。或者,将其“加注”为收藏夹,您将收到任何新答案的通知。
      【解决方案3】:

      一般来说,我认为实体关系使您的编码更容易,尤其是在查询对象时:有什么比说 person.getOption().getDescription() 更容易的呢?但是,这种方法确实有缺点:

      • 必须从数据库中加载引用的实体,尤其是当您有保存级联时。在保存级联中,您可能知道,Hibernate 会抱怨该对象存在于数据库中。我不确定当您没有保存级联时会发生什么。
      • 必须使用单独的查询加载引用的实体,或者在加载主实体时使用外连接。 可能导致性能问题。

      在复杂关系的情况下,将键保留为纯粹的属性可能会有所帮助,例如,当引用一个需要由 Hibernate 完成大量加载的 big 实体时。这种方法有助于减轻系统加载“主”实体的负担。这确实意味着必须自己加载实体,如果你需要它的属性。我想说,对于不可变的“查找”类型实体,您可以安全地保留其实例的内存 Map 并通过它们的键获取()它们,而不是去数据库。不利的一面是您将对实体处理逻辑进行分区:您必须记住要缓存哪些实体并管理它们的缓存。

      我想说,一般来说,使用实体总是更好,毕竟这是您的模型。 Hibernate 坚持指出它可以帮助您持久化您的对象模型来帮助您。然后将尽可能多的持久性内容委托给 Hibernate 是合乎逻辑的。然而,种情况,Hibernate 不能很好地处理“正确”模型:具有许多关系的实体、一直使用的“热”实体等。在这些情况下,如果Hibernate 的机制无济于事(例如 2 级缓存)你真的必须求助于这些“技巧”并自己做一些工作。

      【讨论】:

      • 好吧,在示例中我只有 2 个关系,但在我的应用程序中,我有十多个,在最坏的情况下可能更像 20 个关系。我想我认为实体关系使这些代码的持久性变得更加困难,因为在 UI 端它不会处理对象,而只会处理这些代码。
      【解决方案4】:

      ORM 的全部意义在于为您提供一个对象图,您可以在其中导航并映射到关系数据库。从一个人那里,您应该能够使用person.getOption().getDescription() 获取其选项描述。

      您还应该能够使用

      搜索具有给定选项日期的人
      select p from Person p where p.option.date = :date
      

      这只有在将外键映射为关联而不是字符串时才有可能。

      您不应该使用new Option(code) 将现有选项放入您的人,但是。相反,您应该从会话中获取或加载选项:

      Person p = new Person();
      p.setOption((Option) session.load(Option.class, "ABC"));
      p.setType((Type) session.load(Type.class, "XYZ"));
      session.save(p);
      
      // and now, this code works as expected:
      System.out.println(p.getOption().getDescription());
      

      【讨论】:

      • 拥有对象图肯定是一个优势,但是当我执行 session.save() 时,它会返回填充的实体。另外,我正在使用 Dozer 进行从 Impls(非休眠)到实体和返回的 bean 映射,所以我会在那里遇到问题..
      猜你喜欢
      • 1970-01-01
      • 2013-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-30
      相关资源
      最近更新 更多