如何持久保存仅包含集合和ID的实体?

时间:2016-11-16 14:32:58

标签: database postgresql jpa persistence openjpa

我遇到一个问题,我无法持久化或合并仅包含ID和其他对象集合的对象。如果我添加另一个字段,它将正常提交事务。此外,如果我将ID生成策略更改为AUTO,它也将起作用。

我团队的其他成员使用" IDENTITY"而不是" AUTO",所以我希望与他们保持一致。他们的实体不仅仅是一个ID + Collection,所以它适用于他们。以下是我想要做的工作:

@Entity
public class Filter implements Serializable {

   @Id
   @GeneratedValue( strategy = GenerationType.IDENTITY )
   private Long id;

   @OneToMany( fetch = FetchType.EAGER, orphanRemoval = true, cascade = { CascadeType.ALL } )
   private ArrayList<Rule> rules = new ArrayList<>();

   public Filter() {

   }

}

的ErrorMessage:

org.apache.openjpa.persistence.PersistenceException: ERROR: syntax error at or near ")"
  Position: 25 {prepstmnt 693640431 INSERT INTO Filter () VALUES ()} [code=0, state=42601]
FailedObject: middle.ware.Filter@630cd05

基本上,由于它只是一个ID和一个连接表,它在尝试持久化或合并Filter而没有任何字段时会死掉。

变通方法

  • 将GenerationType.IDENTITY更改为GenerationType.AUTO。

    - 唯一的骗局似乎是初始启动主键跳转50,然后它开始递增1。

  • 将GenerationType更改为TABLE

    - 这似乎是AUTO选择的。

  • 向实体添加任意字段(即String test = &#34;测试&#34;。)

    - 简单地让实体再增加一个字段使其持久化。但是,我不需要这个领域;我只想要一个集合

  • 使关系双向化。

    - 通过使关系双向化,表格会返回一个id(而不仅仅是id)。这仅适用,因为Filter由另一条记录拥有。

2 个答案:

答案 0 :(得分:0)

一个好的解决方案会使代码双向化,正如您已经指出的那样,并使用&#34; @PrePersist&#34;注释,将id设置为&#34;规则&#34;对象。类似的东西:

Rule.java

@Entity
public class Rule implements Serializable {

    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    private Long id;

    private String description;

    @ManyToOne
    private Filter filter;

    // getters, setters, equals, hashcode, toString...
}

Filter.java

@Entity
public class Filter implements Serializable {

    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    private Long id;

    @OneToMany( fetch = FetchType.EAGER, orphanRemoval = true, cascade = { CascadeType.ALL }, mappedBy="filter" )
    private List<Rule> rules = new ArrayList<>();

    @PrePersist
    public void prePersist() {
        if (rules != null) {
            rules.forEach(item -> item.setFilter(this));
        }
    }

    // getters, setters, equals, hashcode, toString...
}

FilterRepository.java

@Repository
public interface FilterRepository extends JpaRepository<Filter, Integer> { }

AnUnitTest.java

@RunWith(SpringRunner.class)
@SpringBootTest
public class AnUnitTest {
    @Autowired
    private FilterRepository filterRepository;

    @After
    public void clearDatabase() {
        bodyPartRespository.deleteAll();

        filterRepository.deleteAll();
    }

    @Test
    public void testFilterRules() {
        Rule aRule = Rule.builder()
                .description("A")
                .build();
        Rule anotherRule = Rule.builder()
                .description("B")
                .build();

        Filter filter = Filter.builder()
                .rules(Arrays.asList(aRule, anotherRule))
                .build();

        filterRepository.saveAndFlush(filter);

        List<Filter> all = filterRepository.findAll();

        all.forEach(System.out::println);
    }
}

上面的代码对我来说运行正常。

我希望这能解决你的问题。

干杯,尼古拉斯。

答案 1 :(得分:0)

我用4个不同的例子实现了你的问题:

  1. 只是ID

      

    @Entity   公共类Case1实现了Serializable {

         

    private static final long serialVersionUID = 1L;

         

    @Id   @GeneratedValue(strategy = GenerationType.IDENTITY)   private Long id;

         

    // ...   }

  2. ID + 1字符串列

      

    @Entity   公共类Case2实现了Serializable {

         

    private static final long serialVersionUID = 1L;

         

    @Id   @GeneratedValue(strategy = GenerationType.IDENTITY)   私人长身份;   私有字符串名称;

         

    // ...   }

  3. ID + 1 OneToMany协会
  4.   

    一个。 with cascade = {CascadeType.ALL}

    > @Entity
    > public class Case3 implements Serializable {
    >         
    > private static final long serialVersionUID = 1L;
    >            
    > @Id
    > @GeneratedValue(strategy = GenerationType.IDENTITY)
    > private Long id;
    > @OneToMany( fetch = FetchType.EAGER, orphanRemoval = true, cascade = { CascadeType.ALL } )
    > private ArrayList<AdminUtilisateur> users = new ArrayList<>();        
    >  // ...
    >}
    
      

    湾没有cascade = {CascadeType.ALL}

    > @Entity
    > public class Case4 implements Serializable {
    >         
    > private static final long serialVersionUID = 1L;
    >            
    > @Id
    > @GeneratedValue(strategy = GenerationType.IDENTITY)
    > private Long id;
    >  
    > @OneToMany( fetch = FetchType.EAGER, orphanRemoval = true)
    > private ArrayList<AdminUtilisateur> users = new ArrayList<>();      
    >  // ...
    >}
    

    SQL查询结果很好(在PostgreSQL 9.3下测试)。 但是使用javax.persistence,我得到了不同的结果:

      
        
    1. 案例1:异常说明:要插入表[DatabaseTable(case1)]的字段列表为空。你必须至少定义   该表的一个映射。
    2.   
    3. 案例2:工作正常。
    4.   
    5. 案例3:本地异常堆栈:异常[EclipseLink-4002](Eclipse持久性服务 - 2.4.0.v20120608-r11652):   org.eclipse.persistence.exceptions.DatabaseException内部   例外:org.postgresql.util.PSQLException:ERREUR:la valeur d'une   clédupliquéeromptla contrainte unique«rule_code_key»
    6.   
    7. 案例4:异常说明:要插入表[DatabaseTable(case4)]的字段列表为空。你必须至少定义   该表的一个映射。
    8.   

    案例1,3和&amp;的错误解释4很简单。

    1. 对于案例3,当您有 cascade = {CascadeType.ALL} 时,orm会在保留过滤器之前尝试保留规则一切都取决于需要,因为我的案例规则它已经存在。

    2. 案例1&amp; 4,您试图仅在表N°1上保留过滤器的ID,并在加入表上保留规则的ID +过滤器的ID。 这意味着过滤器只有ID 设计问题的同义词 =您必须为此表定义至少一个映射。