JPA / Hibernate具有关联列和可空连接列

时间:2016-01-26 16:03:11

标签: java hibernate jpa

我使用PostgreSQL 9.4.5设置了三个表。删除了一些细节。

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可以为空的原因。
  4. 我使用JPA和Hibernate作为我的实现提供程序对此进行了建模。我使用OneToMany关联(组件和文件)以访问关联的连接表元数据和两个ManyToOne关联用于连接表对象表示(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;
       ...
    }
    

    除了我有不确定的插入顺序外,一切正常。

    如果我插入没有文件的组件(1个组件行和1个component_file行),则持久性很好。

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

    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].
    

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

2 个答案:

答案 0 :(得分:0)

尝试添加:

cascade = { CascadeType.PERSIST, CascadeType.MERGE } 

用于ComponentFile中的组件和文件@ManyToOne注释。

答案 1 :(得分:0)

由于您已在mappedBy注释中指定了OneToMany属性,因此请确保您每次都适当地调用ComponentFile.setComponent(...)ComponentFile.setFile(...)来设置关系的另一端您要将ComponentFile添加到ComponentFile实体中的arrayList。

如果您仍然看到相同的错误或者您已经在执行此操作,则发布实体创建和关联逻辑会有所帮助。