Java 在Hibernate中将实体id用作引用

Java 在Hibernate中将实体id用作引用,java,hibernate,jakarta-ee,orm,Java,Hibernate,Jakarta Ee,Orm,我想使用某个实体的标识符保存另一个实体的ref 我正在研究的对象模型是巨大的,相关实体包含大量数据。此外,也有少数几件物品本质上是循环的,我怀疑直接拿着物品将是一个问题 >以下面的例子为例,假设有两个实体A和B: Class A { private String id; private String name; private String type; private String b_id // A reference to instance of B without holding dir

我想使用某个实体的标识符保存另一个实体的ref

我正在研究的对象模型是巨大的,相关实体包含大量数据。此外,也有少数几件物品本质上是循环的,我怀疑直接拿着物品将是一个问题

>以下面的例子为例,假设有两个实体A和B:

Class A
{
private String id;
private String name;
private String type;
private String b_id // A reference to instance of B without holding direct instance
}

Class B
{
private String id;
private String name;
private String type;
}

如何使用Hibernate框架实现这一点

您所写的有两个不同的类,它们彼此没有关系,这就是Hibernate处理它们的方式

当您从Hibernate读取
A
的实例时,您必须返回Hibernate,请求与
A
B\u id
相对应的B实例


我强烈建议您使用普通的对象引用,并让Hibernate有机会完成它的工作。不要因为你认为它无法应付而提前注销它。

你基本上忽视了ORM能给你的力量


请记住,a.getB().getId()不会初始化B实例!只有当您实际访问B的其他方法和属性(或显式查询)时,像Hibernate这样的(好的)ORM才会真正麻烦地获取B。

谢谢您的Ans。我想注意几件事

  • 类A和B是相关的,但我知道告诉Hibernate有关关系的唯一方法是使用普通对象引用。我想知道是否有任何方法可以将
    A类
    B类
    关联起来,而不必将
    B
    的实例保存在
    A
    中。在对象模型中,我是否可以在
    A
    中拥有
    B
    的id,而在数据库中,我可以将B\u id作为外键
    B-->A

  • 我当然希望Hibernate来处理这种情况,但是ref链的深度太大了,以至于对一个对象的查询将导致大量信息流,因为直接的实例成员。所以我认为一种避免这种情况的方法是,在类中只放置其他实体的ref,而不通过外键放置关系来损害数据完整性

  • 另外,一些数据+关系形成了一个类似于图形的结构。保留直接实例引用也可能是一个问题。但我不知道Hibernate在这种情况下是如何工作的


听起来您的用例不需要Hibernate,而是需要一些其他东西,因为您基本上是在“取消发明轮子”。您唯一的选择是延迟加载B,这样当您调用A时,B和它的对象图只会被拉入当您显式调用
getB()

时,我也有同样的问题,我希望能够设置键,但不使用所有延迟加载的东西。我发现hibernate非常脆弱,到处都是错误和神秘的鬼类。到目前为止,这并没有简化我的生活。考虑这一点:

模型(大大简化):

这个测试应该正常吗?错了!奇怪的是,投资组合中仍有25股谷歌股票

基本问题是trade2对象指向一个过时的portfolio对象。上一次undoTrade()操作使用的投资组合仍然拥有75股谷歌股票。请注意,Trade2永远不会过时,因为它只执行了persist()。但是,当对公文包执行update()时,会创建一个额外的副本,而不是更改原始对象(如“persist()”所做的)。我很难理解为什么这种设计不会被认为是愚蠢和容易出错的。这是一个简单的例子。我们不是在讨论并发访问问题或任何花哨的东西。哦,当我尝试刷新trade2时,得到了LazyInitializationException,这完全令人困惑

因此,我的解决方案是使用键,以便每次刷新都是明确的:

Trade {
    ...
    @ManyToOne(targetEntity=Portofio.class)
    @JoinColumn(referenceColumnName="id")
    public Long portfolio_id;
}

或者别的什么。虽然我在这里表达了很多沮丧,但我希望听到一个诚实的解释,说明如何处理这些问题。谢谢。

好的,我知道这是一个旧线程,但这是相当常见的,大多数休眠用户似乎没有意识到,对于我们这些不能在整个请求过程中保持会话打开的人来说,这是一个问题

这样做(使用注释作为示例,因为这是我熟悉的):


这将导致默认情况下不获取b,但即使在会话关闭并通过dozer或gilead之类的工具运行结果后,b_id仍然可用。b_id的映射被设置为insertable=false和updateable=false,因此它是只读的,在写回数据库时将被忽略。要更新关联,您必须设置实际的b字段。

是的,但我需要通过SOAP将这些对象发送给客户机,这样客户机需要有一种方式,可以查询有关关联实体ie b的更多信息,因此我需要提供对b的引用(这意味着有另一个用于SOAP通信的对象模型)或“完整”对象A,即对象A的所有字段加上“完整”对象B,听起来就像您需要一个DAO(数据访问对象)。Hibernate和其他任何东西都无法在不引用实例的情况下持久化对象……一个类始终可以有两个映射—RealA和partialA—一个映射正确,另一个映射为纯值。您可以使用实体名称为同一类创建多个映射。很抱歉将其作为ans发布,但注释将您限制为600个字符。我通过进入Hibernate级别(我使用JPA)解决了我的核心问题:会话会话=(会话)entityManager.getDelegate();更新(p)//返回entityManager.merge(p);事实证明,HibernateAPI对于实际发生的事情是非常优秀和清晰的。我想我可能会完全转向这一点。
Trade trade1 = new Trade("GOOG", 25, portfolio);
Trade trade2 = new Trade("GOOG", 50, portfolio);
portfolio = portfolioDAO.enterTrade(trade1);
portfolio = portfolioDAO.enterTrade(trade2);

portfolio = portfolioSource.undoTrade(trade1, user);
portfolio = portfolioSource.undoTrade(trade2, user);
Assert.assertFalse(portfolio.getPositions().containsKey("GOOG"),
        "after both trades net a position of zero");
Trade {
    ...
    @ManyToOne(targetEntity=Portofio.class)
    @JoinColumn(referenceColumnName="id")
    public Long portfolio_id;
}

Class A
{
private String id;
private String name;
private String type;

@OneToOne(fetch=FetchType.LAZY)
private B b;
@Column(name="b_id", insertable=false, updatable=false)
private String b_id;
}