JPA设置引用的属性而不检索它。最佳做法

时间:2015-09-12 17:34:30

标签: java hibernate jpa

假设我有实体,其中嵌入了实体。 例如(请忽略缺失的注释,getter / setter等):

@Entity
class User {
  private String userId;
  private Set<UserOperation> userOperations;
}

@Entity
class UserOperation {
   private String someString;
   // This is nested referenced entity
   private User user;
}

假设我想插入新的UserOperation,我拥有的只是userId。

我可以这样做:

// We just create new user. There is no interaction to get existing from DB. Totally only 1 insert
User user = new User();
user.setId("someId")

UserOperation uOp = new UserOperation();
uOp.setUser(user);
uOp.setSomeString("just op");
em.persist(uOp);

或者我应该只是这样:

// We retrieve existing user. There is interaction to get it from DB. Totally 1 select and 1 insert
User user = em.find("someId")

UserOperation uOp = new UserOperation();
uOp.setUser(user);
uOp.setSomeString("just op");
em.persist(uOp);

这样做的正确方法是什么?

因为从DB角度来看userOperation表只有String用户引用,所以ID应该足够了。 Java需要一个对象。 致电&#34;新用户&#34;我想避免,现有用户的属性被刷新(因为它们都未设置)或JPA试图插入新用户和操作因主键冲突而失败。

欢迎一些例子。

2 个答案:

答案 0 :(得分:1)

对于您的用例,EntityManager中特别有getReference()方法。它为您提供了id的实体对象,但是不访问DB来创建它。因此,最好的解决方案是稍微修改一下你的第二个解决方案:

// We retrieve a stub user for given id. There is no interaction with DB
User user = em.getReference("someId", User.class);

UserOperation uOp = new UserOperation();
uOp.setUser(user);
uOp.setSomeString("just op");
em.persist(uOp);

<强>解释

getReference()与find()具有相同的逻辑含义,但它会调用DB。结果是它不检查DB表中是否存在具有给定id的行,并且您获得的对象尚未包含数据。但是,在调用get方法时,该对象完全能够加载附加数据。因此,即使通过getReference()检索对象也完全可用 - 实际上它的工作方式与延迟加载相同。

对您的第一个解决方案的旁注:

第一个解决方案不起作用,因为它会创建一个新的实体user然后在将实体存储到数据库(如果它是级联的)时它会失败(持久化总是调用insert并且它会尝试插入用户使用与DB中存在的相同的ID,或者如果用户不是UserOperation,则会失败。要解决此问题,您需要在致电em.merge(user)之前致电 em.persist(userOperation) 。但同样,这会以与em.find()相同的方式调用选择数据库。

答案 1 :(得分:0)

执行此操作的最佳方法是使用第二个示例。我们应该总是尝试直接从db使用实际对象。仅使用数据库参考将会更糟糕。

现在具体谈到Hibernate,使用整个对象更有意义,特别是因为Hibernate的级联,可以和将来(如果设置了级联)更新你持久存储到数据库的子实体。 / p>

好吧,我不得不承认,总是从数据库中获取对象可能会导致一些性能问题,尤其是在数据库获取大量数据之后,因此实现良好且连贯的模型实体始终很重要,并且还要跟踪数据库从您的应用程序中点击,并尝试保持生成的查询较少。

例如,您自己的示例(第二个)干净且易于理解,我会坚持使用这种方法,因为它非常简单。

希望它可以解决你的问题:)