有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

在Hibernate中使用实体id作为引用的java

我想使用某个实体的标识符保存另一个实体的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框架实现这一点


共 (6) 个答案

  1. # 1 楼答案

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

    这样做(以注释为例,因为这是我所熟悉的):

    
    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;
    }
    

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

  2. # 2 楼答案

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

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

  3. # 3 楼答案

    谢谢你的回答。我想说几件事

    • 甲级及甲级;B是相关的,但我知道告诉Hibernate这个关系的唯一方法是使用普通对象引用。我想知道有没有什么方法可以让我把class Aclass B联系起来,而不必把B的实例保存在A。在对象模型中,我可以在A中有一个B的id吗?但是在数据库中,我可以将b_id作为外键B --> A

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

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

  4. # 4 楼答案

    你所写的有两个不同的类,它们彼此没有关系,这就是Hibernate对待它们的方式

    当您从Hibernate读取A的实例时,您必须返回Hibernate,请求对应于Ab_id的B实例

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

  5. # 5 楼答案

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

    模型(大大简化):

    Portfolio {
     ...
     @OneToMany(cascade = {CascadeType.ALL}, fetch=FetchType.EAGER )
     @MapKey(name="symbol")
     public Map<String,Position> positions;
    }
    Position {
        String symbol; int quantity;
    }
    Trade {
        String symbol; int quantity;  // price,etc
     ...
     @ManyToOne() // looser coupling here.
     public Portfolio portfolio;
    }
    

    测试用例(注:“enterTrade()”所做的只是将交易粘贴到交易表中,然后 调整投资组合中的头寸大小,'undoTrade()'仅恢复):

    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");
    

    这个测试应该正常吗?错误的神秘的是,投资组合中仍有25股谷歌股票

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

    所以,我的解决方案是使用密钥,这样每次刷新都是明确的:

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

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

  6. # 6 楼答案

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