Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/390.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用hibernate保存具有引用的依赖实体的实体_Java_Hibernate - Fatal编程技术网

Java 使用hibernate保存具有引用的依赖实体的实体

Java 使用hibernate保存具有引用的依赖实体的实体,java,hibernate,Java,Hibernate,我们使用Hibernate作为持久层,并且具有复杂的对象模型。在不公开真实数据模型的情况下,我想用下面的简单示例来解释这个问题 class Person { private Integer id; //PK private String name; private Account account; // other data, setters, getters } class Account { private Integer id; //PK

我们使用Hibernate作为持久层,并且具有复杂的对象模型。在不公开真实数据模型的情况下,我想用下面的简单示例来解释这个问题

class Person {
    private Integer id; //PK
    private String name;
    private Account account;
    // other data, setters, getters
}


class Account {
    private Integer id; //PK
    // other data, setters, getters
}
DB映射使用HBM定义如下:

 <class name="Person" table="PERSON">
    <id name="id" column="ID">
        <generator class="native"/>
    </id>
    <version name="version" type="java.lang.Long"/>
    <property name="name" type="java.lang.String" length="50" column="NAME"/>
    <many-to-one name="account" column="ACCOUNT_ID"
                class="com.mycompany.model.Account"/>

</class>
为了避免这种情况,我必须按ID找到
Account
的持久化对象,然后调用
person.setAccount(persistedAccount)
。在这种情况下,一切正常

但在现实生活中,我处理的是几十个相互关联的实体。我不想为每个引用编写特殊代码


我想知道这个问题是否有某种通用的解决方案

在*-to-*映射上使用
cascade=“all”
要持久化一个实体,只需要引用它的直接依赖项。这些其他实体引用其他实体的事实并不重要

最好的方法是使用
session.load(Account.class,accountId)
获取引用实体的代理,甚至不需要访问数据库


您所做的是正确的:获取对持久帐户的引用,并将此引用设置到新创建的帐户中。

您是否在
多对一
元素中尝试过
cascade=“save update”
?Hibernate默认为
cascade=“none”

谢谢您的帮助。我已经实现了自己的通用解决方案,但想知道是否存在其他解决方案

我想和你分享这个想法。我调用引用的实体,这些实体不包含除ID(或可用于唯一标识实体的其他字段)以外的任何内容。
占位符

因此,我创建了annotation@Placeholder并将其放在所有引用的字段上。在我们的示例中,它是Person类的on account字段。 我们已经有了一个名为
GenericDao
的类,它包装了HibernateAPI,并有方法
save()
。我添加了另一个方法
saveWithPlacehodlers()
,它执行以下操作。它通过反射发现给定对象的类,查找所有标记有注释的字段,在DB中查找对象,并在主实体中调用相应的setter,以持久实体替换引用的占位符

注释
@Placeholder
允许定义用于标识实体的字段。默认值为
id


伙计们,你们觉得这个解决方案怎么样

Hibernate允许您只使用ID为的引用类,而不需要执行session.load()

唯一重要的是,如果引用对象具有版本,则必须设置版本。
在您的情况下,您必须指定Account对象的版本。

还有一个解决方案-使用您想要引用的实体的默认构造函数,并设置id和版本(如果版本控制)。我们有以下dao方法:

public <S extends T> S materialize(EId<S> entityId, Class<S> entityClass) {
        Constructor<S> c = entityClass.getDeclaredConstructor();
        c.setAccessible(true);

        S instance = c.newInstance();
        Fields.set(instance, "id", entityId.getId());
        Fields.set(instance, "version", entityId.getVersion());
        return instance; // Try catch omitted for brevity.
}
public的物化(EId entityId,类entityClass){
构造函数c=entityClass.getDeclaredConstructor();
c、 setAccessible(true);
S instance=c.newInstance();
Fields.set(实例“id”,entityId.getId());
Fields.set(实例“version”,entityId.getVersion());
return instance;//为简洁起见,请尝试省略catch。
}
我们可以使用这种方法,因为我们不使用延迟加载,而是拥有GUI上使用的实体的“视图”。这使我们能够摆脱Hibernate用来填充所有渴望的关系的所有连接。视图始终具有实体的id和版本。因此,我们可以通过创建一个对象来填充引用,该对象看起来是休眠的,而不是瞬态的


我尝试了这种方法和session.load()方法。他们都干得很好。我认为我的方法有一些优势,因为Hibernate不会在代码的其他地方泄漏它的代理。如果没有正确使用,我将只获取NPE,而不是“没有会话绑定到线程”异常。

@Bozho,我添加了
cascade
。事实上我只是忘了说我已经玩过了。现在,当我尝试使用持有合法ID的临时帐户保存person时,我得到如下异常:
org.hibernate.AssertionFailure:com.mycompany.model.person条目中的空ID(在异常发生后不要刷新会话)
我尝试过,@Nacho。它不能正常工作。它引发了另一个例外(请参阅我对Bozho答案的评论。谢谢你,@JB Nizet。这实际上是我所期望的……我将在这里发布我的通用解决方案的描述,并很高兴知道你的意见。这些“自动”必须小心处理解决方案。如果我正确理解您的描述,您将在Save方法中解析依赖关系,该方法一次处理一个对象。如果您在一个工作单元中保存大量对象,则将逐个加载所有依赖对象,这是非常低效的。通常情况下,数据库操作已完成通过存储库或服务类,这两个类都应该对自己的工作有很好的了解。它们可以一次加载许多实体(例如,使用in子句)或者还要验证依赖实体是否已经被持久化。这在Hibernate文档或任何其他可用文档中都有描述吗?爱你的人!我将该版本添加到我的类中,但我无法再通过设置ID来保存它,这浪费了很多时间。我希望JPA能够这样做。可以告诉JPA吗“请保留该引用并使用最新版本”,而无需手动调整对象图?在某些用例中,我确实不关心版本,但我需要此引用。
public <S extends T> S materialize(EId<S> entityId, Class<S> entityClass) {
        Constructor<S> c = entityClass.getDeclaredConstructor();
        c.setAccessible(true);

        S instance = c.newInstance();
        Fields.set(instance, "id", entityId.getId());
        Fields.set(instance, "version", entityId.getVersion());
        return instance; // Try catch omitted for brevity.
}