Reputation: 1157
I have the following structure: tables "parents" and "children", which are binded by parents.id = children.parent_id
Application reads data from these tables into the object of the following class:
public class Parent {
private int id;
private Map<String, String> children;
....
}
Then application changes data in it. What I need to do is to apply changes to existing records. I am not allowed to change Parent class or database structure. And I am trying to do this by using jpa repository by the following way:
My entities
@Repository
public interface ParentsDao extends JpaRepository<ParentEntity, Integer> {
}
@Entity
@Table(name = "parents")
public class ParentEntity {
@Id
@GeneratedValue
@Column(name = "id", updatable = false, insertable = false)
private Integer id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
@JoinColumn(name="parent_id")
private Set<ChildEntity> children;
...
}
@Entity
@Table(name = "children")
public class ChildEntity {
@Id
@GeneratedValue
@Column(name = "id", updatable = false, insertable = false)
private Integer id;
@ManyToOne
@JoinColumn(name="parent_id", updatable = false)
private ScheduledReportsEntity scheduledReport;
@Column(name = "child_name")
private String name;
@Column(name = "child_value")
private String value;
...
}
The following is my sevice, where action() starts the whole thing: converts Parent to ParentEntity and saves it
public class ParentServiceImpl {
@Autowired
ParentsDao parentsDao;
public
void action(Parent parent) {
ParentEntity entity = convert(parent); // moving data from Parent to ParentEntity object
parentsDao.save(entity); //here I receive exception
}
private ParentEntity convert(Parent parent) {
Set<ChildEntity> children = new HashSet<ChildEntity>();
for(Map.Entry<String, String> entry : simpleObj.getChildren().entrySet()){
ChildEntity childEntity = new ChildEntity();
childEntity.setName(entry.getKey());
childEntity.setValue(entry.getValue());
children.add(entity);
}
ParentEntity entity = new ParentEntity();
entity.setId(parent.getId());
entity.setChildren(children);
return entity;
}
}
But I am receiving the following error:
com.app.impl.ParentServiceImpl: org.springframework.dao.DataIntegrityViolationException:
could not insert: [com.app.entities.ChildEntity];
SQL [insert into scheduled_report_params (child_name, child_value, parent_id) values (?, ?, ?)];
constraint [null];
nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [com.app.entities.ChildEntity]
I have 2 questions: 1. I think this is connected to missing ids in children, am I right? 2. If the reason is missing ids, then are there any way to get around it somehow and provide save by other fields? Will be greatfull for any advice. Thanks
Upvotes: 0
Views: 3834
Reputation: 148880
You have a design problem.
You are right, if id
is the primary key for child entity, it must be present in all pre-existent (not new) ChildEntity
elements from the children Set of a ParentEntity
element if you modify it. If not, Hibernate will try to insert them.
So you must choose between two solutions :
use a generated primary key in ChildEntity
and find a way to keep it in your application. For example, you could use ParentEntity
as the real model class with Parent
being a view on it :
class Parent {
private ParentEntity inner;
public Parent(ParentEntity entity) {
inner = entity;
// initialize children or have getChildren to dynamically create it
// from inner.childre
...
}
...
}
use child name as the primay key. The ChildEntity
would look like :
@Entity
@Table(name = "children")
public class ChildEntity {
@Id
@Column(name = "child_name")
private String name;
@Column(name = "child_value")
private String value;
@ManyToOne
@JoinColumn(name="parent_id", updatable = false)
private ScheduledReportsEntity scheduledReport;
...
}
But you cannot simply forget a primary key in your application.
Upvotes: 2