2016-01-26 73 views
0

我有三个表使用PostgreSQL 9.4.5进行设置。删除了一些细节。JPA /休眠多对多关联列和可空连接列

Table: component 
id | bigint | not null default nextval('component_seq'::regclass) | 

Table: file 
id | bigint | not null default nextval('file_seq'::regclass) | 

Table: component_file 
id   | bigint | not null default nextval('component_file_seq'::regclass) | 
component_id | bigint | not null | 
file_id  | bigint |    | 
usage  | text | not null | 

从本质上讲,它与多对多连接表中的附加列是多对多的关系。

  1. 一个文件可以关联到一个或多个组件。
  2. 组件可以关联到一个或多个文件。
  3. 组件可能与没有文件关联,这就是为什么component_file.file_id可为空。

我已经使用JPA和Hibernate作为我的实现提供者对此进行了建模。我使用一对多协会(组件和文件),以有机会获得相关的连接表的元数据和连接表对象表示2个多对一协会(ComponentFile)

public class Component { 
    ... 
    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "component_seq") 
    @Column(name = "id", nullable = false, insertable = true, updateable = false) 
    private Long id; 

    @OneToMany(mappedBy = "component", cascade = { CascadeType.PERSIST, CascadeType.MERGE }, fetch = FetchType.LAZY, orphanRemoval = true) 
    private List<ComponentFile> componentFiles; 
    ... 
} 

public class File { 
    ... 
    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "file_seq") 
    @Column(name = "id", nullable = false, insertable = true, updateable = false) 
    private Long id; 

    @OneToMany(mappedBy = "file", cascade = { CascadeType.PERSIST, CascadeType.MERGE }, fetch = FetchType.LAZY, orphanRemoval = true) 
    private List<ComponentFile> componentFiles; 
    ... 
} 

public class ComponentFile { 
    ... 
    @ManyToOne(fetch = FetchType.LAZY, optional = false) 
    @JoinColumn(name = "component_id", referencedColumnName = "id", nullable = false, insertable = true, updateable = false) 
    private Component component; 

    @ManyToOne(fetch = FetchType.LAZY, optional = true) 
    @JoinColumn(name = "file_id", referencedColumnName = "id", nullable = true, insertable = true, updateable = false) 
    private File file; 
    ... 
} 

所有工作正常,除非我有indeterminite插入顺序。

如果我插入一个没有文件的组件(1个组件行和1个组件行),持久性就没有问题。

如果我插入与单个文件关联的多个组件(1个组件行,2个文件行,2个component_file行),则会发生错误,因为Hibernate正在插入带有空file_id引用的component_file行。这会导致违反约束条件,因为Hibernate正在插入具有相同组件ID和NULL文件ID(不允许使用component_file.component_id,其中component_file.file_id为NULL)的两行。

2016-01-26 10:59:30,506 ERROR [SqlExceptionHelper] - Batch entry 1 insert into component_file (usage, component_id, file_id, id) values ('INCLUDED', '180', NULL, '202') was aborted. Call getNextException to see the cause. 
2016-01-26 10:59:30,506 WARN [SqlExceptionHelper] - SQL Error: 0, SQLState: 23505 
2016-01-26 10:59:30,507 ERROR [SqlExceptionHelper] - ERROR: duplicate key value violates unique constraint "uidx_component_file_component_id" Detail: Key (component_id)=(180) already exists. 
2016-01-26 10:59:30,509 ERROR [BatchingBatch] - HHH000315: Exception executing batch [could not execute batch] 
2016-01-26 10:59:30,512 INFO [DbConstraintNameRetriever] - Constraint name retrieval results [Name: uidx_component_file_component_id | Original class: java.sql.BatchUpdateException | Message: ERROR: duplicate key value violates unique constraint "uidx_component_file_component_id" Detail: Key (component_id)=(180) already exists. | Postgres exception?: true | Batch update exception?: true]. 

为什么会发生这种情况,以及解决这种类型的关系和持久性的解决方法或替代方法是什么?

回答

0

尝试添加:

cascade = { CascadeType.PERSIST, CascadeType.MERGE } 

的组件和ComponentFile文件@ManyToOne注解。

+0

这是我的问题的根源...谢谢。 – user3699312

0

既然你已经在OneToMany注解指定mappedBy属性,请确保您也可以通过调用ComponentFile.setComponent(...)ComponentFile.setFile(...)适当每当你在ComponentFile实体添加ComponentFile到ArrayList设置关系的另一端。

如果您仍然看到相同的错误,或者您已经在使用它,发布实体创建和关联逻辑将有所帮助。