Spring 使用Hibernate插入子对象不会返回完整对象

Spring 使用Hibernate插入子对象不会返回完整对象,spring,hibernate,jpa,foreign-keys,parent-child,Spring,Hibernate,Jpa,Foreign Keys,Parent Child,我正在使用Spring3.2、HibernateCore4.1.4和hibernate-jpa-2.0.1。应用程序资源文件具有所有正确的对象 我有一个子对象RoleEntity,它有两个父对象:User和Award,因此userId和awardId是已经存在的外键,并且必须存在才能创建角色实体 public class RoleEntity implements Serializable { @Id @GeneratedValue(strategy = GenerationTy

我正在使用Spring3.2、HibernateCore4.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时,我可以完全恢复加载的对象,并且用户和奖励都已完全填充

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

  • 将roleId设置为0,角色描述
  • 创建userEntity并仅设置id,此id已存在且不是新的
  • 创建awardEntity并仅设置id,此id已存在且不是新的
  • 我可以成功地做一个保存,这是伟大的!!!!对我有用。 在新对象返回中,我可以清楚地看到新角色ID已返回给我!!! RoleEntity的所有其他字段,如描述,都在那里

    但是,我也希望RoleEntity的用户和奖励字段完全填充,就像我在插入后进行了选择一样。这可能吗

    我不希望对用户进行选择并奖励表来获取这些对象,然后将它们分配给这个对象,但是如果我必须这样做,那也没关系

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

    试试这种方法:

    sess.save(角色)
    sess.flush()//强制SQL插入
    更新(角色);

    这里有两件事。首先,您不应该仅仅为了使用此ID而创建具有已知ID的新的实体。这种方法是一种等待发生的意外情况:具有此ID的实体已经存在,并且由于此重复键,您将遇到
    ConstraintViolationException
    UnonqueObjectException

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

    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能够做到这一点的唯一方法是使用(L2C),但从您的问题来看,我假设没有L2C

    即使您的
    @ManyToOne
    关联是急切获取的,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属性,就会从数据库中选择相应的实体

    UserEntity user = session.load(UserEntity.class, userId);
    AwardEntity award = session.load(AwardEntity.class, awardId);
    
    也就是说,为了更好地理解,我建议大家看看Hibernate。如果您想在生产级别上使用Hibernate,还应该阅读一本很好的Hibernate书籍,如

    希望这有帮助