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 将主键映射为外键的@OneToMany关系_Java_Hibernate_Jpa - Fatal编程技术网

Java 将主键映射为外键的@OneToMany关系

Java 将主键映射为外键的@OneToMany关系,java,hibernate,jpa,Java,Hibernate,Jpa,我试图映射JPA中下图中描述的一对多表关系: 可以看出,“activity\u属性”表使用了一个复合主键,(id,name),列“id”是表“activity”中列“id”的外键 我当前的实体是这样映射的(为了清晰起见,已经使用了一些辅助方法): Activity.java @实体 @吸气剂 @塞特 公共课堂活动{ @身份证 @GeneratedValue(策略=GenerationType.SEQUENCE,generator=“act\u id\u generator”) @Sequenc

我试图映射JPA中下图中描述的一对多表关系:

可以看出,
“activity\u属性”
表使用了一个复合主键,
(id,name)
,列
“id”
是表
“activity”
中列
“id”
的外键

我当前的实体是这样映射的(为了清晰起见,已经使用了一些辅助方法):

Activity.java
@实体
@吸气剂
@塞特
公共课堂活动{
@身份证
@GeneratedValue(策略=GenerationType.SEQUENCE,generator=“act\u id\u generator”)
@SequenceGenerator(name=“act\u id\u generator”,sequenceName=“activity\u id\u seq”,allocationSize=1,initialValue=1)
私有整数id;
私有字符串名称;
@OneToMany(mappedBy=“id.activityId”,cascade=CascadeType.ALL,orphanRemoving=true)
私有财产清单;
}
ActivityProperty.java
@实体
@吸气剂
@塞特
@表(name=“活动\财产”)
公共类活动属性{
@嵌入ID
私有活动属性id;
私有字符串值;
@枚举(EnumType.STRING)
私有财产类型;
}
ActivityPropertyId.java
@可嵌入
@吸气剂
@塞特
@托斯特林
公共类ActivityPropertyId实现可序列化{
@列(name=“id”)
私有整数活动ID;
私有字符串名称;
@凌驾
公共布尔等于(对象o){
如果(this==o)返回true;
如果(o==null | | getClass()!=o.getClass())返回false;
ActivityPropertyId,该值=(ActivityPropertyId)o;
返回activityId.equals(即.activityId)&&
name.equals(that.name);
}
@凌驾
公共int hashCode(){
返回Objects.hash(activityId,name);
}
}
当我尝试以这种方式保持活动时:

Activity-Activity=createActivity(“Activity_1”);
activity.addProperty(ActivityProperty.from(“Prop1”,“value1”,PropertyType.PARAMETER));
坚持(活动);
我可以在Hibernate中看到以下跟踪:

Hibernate: call next value for activity_id_seq
Hibernate: insert into activity (name, id) values (?, ?)
Hibernate: insert into activity_property (type, value, id, name) values (?, ?, ?, ?)
05-05-2019 12:26:29.623 [main] WARN  o.h.e.jdbc.spi.SqlExceptionHelper.logExceptions - SQL Error: 23502, SQLState: 23502
05-05-2019 12:26:29.624 [main] ERROR o.h.e.jdbc.spi.SqlExceptionHelper.logExceptions - NULL not allowed for column "ID"; SQL statement:
insert into activity_property (type, value, id, name) values (?, ?, ?, ?) [23502-199]
活动
的自动生成Id似乎未在
活动属性
的第二次插入中使用


我不知道如何正确映射这种关系。我的JPA批注中是否缺少任何内容?

属性
mappedBy
用于指示此关系不用于持久化,而
mappedBy
中的属性用于此目的

因此,要么创建一个从
ActivityProperty
Activity
的反向引用,并使用映射的反向引用,要么必须使用
@JoinColumn
来声明外键

那看起来像。属性
name
指向目标表中外键的名称

@JoinColumn(name = "id", nullable = false)
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private List<ActivityProperty> properties;

在这里阅读有关关系映射的更多信息:

据我所知,JPA不支持通过
cascade
操作进行映射。你对JPA的要求太高了。我并没有一个具体的参考来说明这一点,但您可以通过下面的代码尽可能接近它。它不会运行,因为hibernate(至少)不知道如何自动将
activity.id
映射到
ActivityProperty
类的PK

@Entity
@Getter
@Setter
@Table(name = "activity_property")
@IdClass(ActivityPropertyId.class)
public class ActivityProperty {
    @ManyToOne
    @Id
    @JoinColumn(name="id", referencedColumnName="id")
    private Activity activity;

    @Id
    private String name;
    private String value;

}

@Getter
@Setter
@ToString
public class ActivityPropertyId implements Serializable {
    public ActivityPropertyId() {}

    @Column(name = "id")
    private Integer activity;

    private String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ActivityPropertyId that = (ActivityPropertyId) o;
        return activity.equals(that.activity) &&
                name.equals(that.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(activity, name);
    }
}
这将是一个例外

原因:java.lang.IllegalArgumentException:无法将java.lang.Integer字段model.ActivityPropertyId.activity设置为model.activity


我还没有找到解决这个问题的好办法。IMHO
cascade
是傻瓜的天堂,您应该自己保存
ActivityProperty
实例,并且只对查询使用双向映射。这就是它的真正用途。如果您通过级联对
OneToMany
列表执行一些简单的保存操作,并查看生成的SQL,您将看到可怕的事情。

恐怕这与
@JoinColumn
注释没有区别,插入属性时id仍然为空:(,我们真的需要使其具有双向性并保留对完整活动对象的引用吗?似乎有点开销。将nullable=false添加到JoinColumn中。我在添加
nullable=false
时更新了我的答案,现在我发现
无法构建Hibernate SessionFactory;嵌套异常为org.Hibernate.MappingException:Re实体映射中的重复列:com.gmv.epssg.oas.model.entity.db.ActivityProperty列:id(应使用insert=“false”update=“false”进行映射)
我忘记了必须将activityId设置为只读。我已将此添加到我的答案中。很抱歉,已尝试将这些属性添加到activityId中,但出现相同错误:(好的,非常感谢您的建议。我想我将排除级联并手动保留该关系。非常感谢!我按照您的建议删除级联插入并保留
@OneToMany
注释仅用于查询目的。
@Entity
@Getter
@Setter
@Table(name = "activity_property")
@IdClass(ActivityPropertyId.class)
public class ActivityProperty {
    @ManyToOne
    @Id
    @JoinColumn(name="id", referencedColumnName="id")
    private Activity activity;

    @Id
    private String name;
    private String value;

}

@Getter
@Setter
@ToString
public class ActivityPropertyId implements Serializable {
    public ActivityPropertyId() {}

    @Column(name = "id")
    private Integer activity;

    private String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ActivityPropertyId that = (ActivityPropertyId) o;
        return activity.equals(that.activity) &&
                name.equals(that.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(activity, name);
    }
}