3

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

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)

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

什么是更好的对象关系与键与两者?

只需使用键:

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

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

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

您认为不同方式的优缺点是什么?如果我只是将两者都放入 Person 对象中,这样我就可以使用更方便的方法了怎么办?制作只将字符串推入新的选项/类型实体的设置器怎么样?

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

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

4

4 回答 4

2

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());
于 2011-09-16T16:41:43.983 回答
1

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

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

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

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

于 2011-09-16T16:48:24.240 回答
0

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

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

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

不过,我们怀疑我们很快就会看到这个。

于 2012-01-04T23:38:01.850 回答
0

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

于 2011-09-21T12:00:11.460 回答