使用带有子对象的Hibernate插入不会返回完整对象

时间:2013-02-01 21:15:02

标签: spring hibernate jpa foreign-keys parent-child

我使用的是Spring 3.2和hibernate-core 4.1.4以及hibernate-jpa-2.0.1。应用程序资源文件包含所有正确的对象。

我有一个子对象RoleEntity,它有两个父对象:User和Award,因此userId和awardId是已经存在的外键,并且必须存在才能创建角色实体。

public class RoleEntity implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "role_id")
    private long roleId;

    @Column(name = "role_description")
    private String roleDescription;

    @Column(name = "role_name")
    private String roleName;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id")
    private UserEntity user;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "award_id")
    private AwardEntity award;

     ... getters/setters
     ... hash/equals/toString
}

我的DAO插页看起来非常简单:

@Override
public RoleEntity saveRoleEntity(RoleEntity role)
{
     logger.debug("saveRoleEntity: role=" + role);
     return role;
}

我已经对这段代码进行了单元测试,我可以确认,当我选择一个现有的roleId时,我可以完全取回已加载的对象,并完全填充User和Award。

但是,当我插入新角色时,我会执行以下操作:

  1. 将roleId设置为0,并将角色描述...
  2. 创建userEntity并仅设置id,此ID已存在且不是新的
  3. 创建一个awardEntity并仅设置id,此ID已经存在并且不是新的
  4. 我可以成功保存,这很棒!!!!适合我。 并且在新的对象返回中,我可以清楚地看到新的roleId返回给我!!! 所有其他字段都是RoleEntity,就像说明那样。

    但是,我个人想要的是完全填充RoleEntity的User和Award字段,就好像我在插入后完成了select一样。这甚至可能吗?

    我更愿意不对用户进行选择并奖励表格以获取这些对象,然后将它们分配给此对象,但如果我必须这样做,那就没关系。

    如果我需要提供更多信息,请告诉我。 感谢您提前提供任何帮助。

2 个答案:

答案 0 :(得分:1)

尝试这种方法:

sess.save(role);
sess.flush(); //force the SQL INSERT
sess.refresh(role);

答案 1 :(得分:0)

这里有两件事。首先,您不应仅使用此ID创建具有已知ID的实体。这种方法是一个等待发生的事故:具有此ID的实体已经存在,并且由于此重复密钥,您将遇到ConstraintViolationExceptionNonUniqueObjectException

如果你想使用具有已知ID的实体但你不想从数据库中选择完整的实体,那么使用Hibernate你可以使用代理

UserEntity user = session.load(UserEntity.class, userId);
AwardEntity award = session.load(AwardEntity.class, awardId);

这不会命中数据库来选择实体,但会返回代理(包装已知的id)。在同一个会话中,您可以像使用完整实体一样使用代理并创建新的RoleEntity

RoleEntity role = new RoleEntity();
role.setUser(user);
role.setAward(award);
session.save(role);

第二件事是:Hibernate 如何知道实体的非id属性而不会访问数据库!? Hibernate可以做到这一点的唯一方法是使用Second Level Cache(L2C),但是根据你的问题我假设没有L2C。

即使你的@ManyToOne关联是 eager-fetched ,Hibernate必须访问数据库以填充相应的实体。因此,您可以使用@Bogdan的答案中的方法,并在插入后重新加载角色以及关联的用户和奖励实体

session.save(role);
session.refresh(role);

但是,与首先选择相应实体以将其分配给新角色

相比,这没有任何性能优势
UserEntity user = session.get(UserEntity.class, userId);
AwardEntity award = session.get(AwardEntity.class, awardId);    

这将立即命中数据库并填充您的实体(如果不存在具有给定ID的行,则返回null)。

请注意,在使用代理时,您可以在同一会话中按需按需填充实体。一旦访问了非id属性,就从数据库中选择相应的实体。

那就是说,我建议你看一下Hibernate docs以便更好地理解。如果你想在生产级别上使用Hibernate,你还应该阅读一本好的Hibernate书,如Java Persistence with Hibernate

希望这会有所帮助。