休眠持久化实体而不获取关联对象。仅凭身份证

Posted

技术标签:

【中文标题】休眠持久化实体而不获取关联对象。仅凭身份证【英文标题】:Hibernate persist entity without fetching association object. just by id 【发布时间】:2015-08-10 21:24:27 【问题描述】:

我在 2 个实体之间有一个简单的关联:

public class Car 

    ...

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    ...


public class User 

    @Id
    @GeneratedValue
    @Column(name = "user_id")
    private long userId;

    ...

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
    private Set<Car> cars;

    ...


然后我从客户端获得一些用户 ID。例如,userId == 5; 为了与用户一起保存汽车,我需要执行以下操作:

User user = ... .findOne(userId);  
Car car = new Car();
car.setUser(user);
... .save(car);

我的问题是:我可以在不获取用户的情况下保留汽车记录吗?

与使用本机 SQL 查询类似:只需在 Car 表中插入 userId,如 string(long)。 使用 2nd lvl 缓存会更快,但我认为我不需要做额外的动作。 我不想使用本机 Query 的主要原因是因为我的项目中的关联要困难得多,我需要 .save(car) 多次。此外,我不想手动控制查询执行的顺序。如果我使用 session.createSQLQuery("insert into .....values()") 将 Hibernate 的批量插入工作正常?

如果我错了,请纠正我。 提前致谢! 更新: 实际上映射类似于:

User 和 Car 之间存在 @ManyToMany 关联。但是交叉表也是一个被命名的实体,例如Passanger。所以接下来是映射:

public class User
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user", targetEntity = Passenger.class)
    private Set<Passenger> passengers;

跨实体

@IdClass(value = PassengerPK.class)
public class Passenger 

    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "car_id")
    private Car car;

    ... other fields ...


汽车实体:

public class Car 
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "car", targetEntity = Passenger.class, cascade = CascadeType.ALL)
    private Set<Passenger> passengers;

还有代码:

List<User> users = ... .findInUserIds(userIds); // find user records where userId is IN userIds - collection with user Ids
Car car = new Car();       //initialization of car's fields is omitted
if (users != null) 
    car.setPassengers(new HashSet<>(users.size()));
    users.forEach((user) -> car.getPassengers().add(new Passenger(user, car)));

... .save(car);

【问题讨论】:

您是否显示了确切的映射?从CarUser 没有级联? @DraganBozanovic,我已经更新了帖子。是的,有级联。 【参考方案1】:

“我可以在不获取用户的情况下保留汽车记录吗?”

是的,这是 Hibernate 代理的优点之一:

User user = entityManager.getReference(User.class, userId); // session.load() for native Session API  
Car car = new Car();
car.setUser(user);

这里的重点是使用EntityManager.getReference:

获取一个实例,其状态可能会被延迟获取。

Hibernate 只会根据提供的 id 创建代理,而不从数据库中获取实体。

“如果我使用 session.createSQLQuery("insert into .....values()") 将 Hibernate 的批量插入工作正常吗?”

不,不会。查询会立即执行。

【讨论】:

你是对的。但如果你允许,我还有另一个问题。由于异常,我无法调用 .merge(car):分离实体传递给持久化?调用 saveOrUpdate() 不是一个选项,因为我需要 removeOrphan。 我建议您为此打开一个不同的问题,因为这似乎是一个不同的问题。在那里发布异常的整个堆栈跟踪,以便我们知道哪个实体被分离,等等。 我打开了新问题。请访问LINK 使用 eclipselink 您根本不需要获取参考。是在路上处理的。是否可以以相同的方式配置休眠? 这对于单个对象来说似乎没问题。是否有保存实体列表的选项。例如,如果我想用不同的用户保存汽车列表?【参考方案2】:

如果有人在使用spring JPA,同样可以在Spring JPA中使用方法

getOne(userId)

【讨论】:

【参考方案3】:

Hibernate 用户可以实现这个方法:

public <T extends Object> T getReferenceObject(Class<T> clazz, Serializable id) 
        return getCurrentSession().get(clazz, id);
    

然后像这样调用:

MyEntity myEntity = getRefererenceObject(MyEntity.class, 1);

您可以根据您的实体模型将 id 类型更改为 Integer 或 Long。 或者,如果您对所有实体都有一个基类,则 T 可以从您的 BaseEntity 继承。

【讨论】:

【参考方案4】:

以下方法对我有用:

User user = new User();
user.setId(userId);
car.setUser(user);

【讨论】:

这是一个临时实体,它不会持久化。

以上是关于休眠持久化实体而不获取关联对象。仅凭身份证的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot:仅访问 JPA 中的关联列值而不获取完整的关联实体

hibernate对象的三种状态是啥?

Symfony2:获取持久化对象的 id

NHibernate总结

MyBatis关联映射:一对一一对多总结一二

休眠:具有相同标识符值的不同对象已与会话相关联[重复]