How to save an object that contains only the collection and identifier?

I have a problem where I cannot save or merge an object containing only ID and a collection of other objects. If I add another field, it will complete the transaction as usual. Also, if I change the ID generation strategy to AUTO, it will also work.

The rest of my team uses "IDENTITY" instead of "AUTO", so I want to be in agreement with them. Their entities are more than just an ID + collection, so they are great for them. Here is what I want to do:

@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 

Essentially, since it's just an identifier and a connection table, it dies when you try to save or merge a filter without any fields.

Bypass

  • Change GenerationType.IDENTITY to GenerationType.AUTO.

    . The only conflict seems to be that the initial initial primary keys jump by 50, then it starts to increase by 1.

  • Change GenerationType to TABLE

    -This is like choosing AUTO.

  • Add an arbitrary field to the object (i.e. String test = "Test").

    - Simple creation of an object with one more field makes it persistent. However, I do not need this field; I just need a collection

  • Make the relationship bidirectional.

    - By setting up a bidirectional relationship, tables return id (instead of just being id). This only works because Filter belongs to another record.

+6
source share
2 answers

A good solution will make the code bidirectional, as you have already indicated, and use the annotation "@PrePersist" to set the identifier to the "Rules" objects. Sort of:

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); } } 

The above code is great for me.

I hope this solves your problem.

Greetings, Nicholas.

0
source

I implemented your problem with 4 different examples:

  • Id only

    @Entity public class Case1 implements Serializable {

    closed static final long serialVersionUID = 1L;

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

    // ...}

  • Column row ID + 1

    @Entity The Case2 public class implements Serializable {

    closed static final long serialVersionUID = 1L;

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

    // ...}

  • Association ID + 1 OneToMany

a. cascaded = {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<>(); > // ... >} 

b. without 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<>(); > // ... >} 

The results were in order with SQL queries (tested in PostgreSQL 9.3). But with javax.persistence, I have different results:

  • Case 1: Exception Description: The list of fields to insert into the [DatabaseTable (case1)] table is empty. You must define at least one mapping for this table.
  • Case 2: it works fine.
  • Case 3: Local Exception Stack: Exception [EclipseLink-4002] (Eclipse State Conservation Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: org.postgresql.util.PSQLException: ERREUR: la valeur d'une clé dupliquée rompt la contrainte unique "rule_code_key"
  • Case 4: Exception Description: The list of fields to insert into the [DatabaseTable (case4)] table is empty. You must define at least one mapping for this table.

The explication of errors in cases 1, 3 and 4 is simple.

  • For case 3, when you have cascade = {CascadeType.ALL} , the command tries to save the rule before saving the Filter and it all depends on the need, for my case the Rule already exists.

  • For cases 1 and 4, you are trying to save only the Filter identifier in table N ° 1 and the rule id + filter identifier on the Attach table . This means that the filter only has a synonym identifier for the design problem = you must define at least one mapping for this table.

0
source

Source: https://habr.com/ru/post/1012376/


All Articles