How to make a collection valued property read only in JPA - java

I've got a collection valued property of a basic (non-entity) type that I want to make read only. I've managed to exclude the column from insert and update sql queries, but I cannot do the same for delete queries, so if the containing entity has an empty list of said property, all of them get deleted from the database:
#Entity
public class Parent {
#Column(name = "CHILD_ID", insertable = false, updatable = false)
#ElementCollection(fetch = FetchType.LAZY)
#CollectionTable(name = "T_REL_PARENT_CHILD", joinColumns = #JoinColumn(name = "PARENT_ID", insertable = false, updatable = false))
private List<Long> childIds;
}

Related

#ManyToOne in self-referencing entity with composite key - #IdClass, java, hibernate

Spent 3 days looking for a solution and finally I came here for community wisdom.
I have self-referencing entity like follows:
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#IdClass(CompositeUserId.class)
#Table(name = "user", schema = "dbo")
public class User implements Serializable {
#Id
#Column(name = "id")
private Integer id;
#Id
#Column(name = "first_name")
private String firstName;
#Id
#Column(name = "last_name")
private String lastName;
#ManyToOne
#JoinColumn(name = "parent_id", referencedColumnName = "id", insertable = false, updatable = false)
#JoinColumn(name = "first_name", referencedColumnName = "first_name", insertable = false, updatable = false)
#JoinColumn(name = "last_name", referencedColumnName = "last_name", insertable = false, updatable = false)
private User parent;
#OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
private Set<User> children;
my CompositeUserId.class:
#Getter
#Setter
#EqualsAndHashCode
#AllArgsConstructor
#NoArgsConstructor
public class UserCompositeId implements Serializable {
private Integer id;
private String firstName;
private String lastName;
When I try retrieve all data from my user table I get error:
org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find ...User with id UserCompositeId#19e66569; nested exception is javax.persistence.EntityNotFoundException:
I suppose there might be some kind of mistake in the #JoinColumn block.
Here is the sql query causing the error:
SELECT *
FROM dbo.user ur1 LEFT OUTER JOIN dbo.user ur2 ON ur1.first_name=ur2.first_name AND ur1.parent_id=ur2.id AND ur1.last_name=ur2.last_name
WHERE ur1.first_name='First Name' AND ur1.id=130 AND ur1.last_name='Last Name'
I ensured that the request does not return anything in the database by running it manually, but found out that if I will change id to parent_id it will return data, so again, probably some mistake in #JoinColumn block
You need you use #NotFound(action=NotFoundAction.IGNORE). If there is no records then it will assign null to it.
#ManyToOne
#JoinColumn(name = "parent_id", referencedColumnName = "id", insertable = false, updatable = false)
#JoinColumn(name = "first_name", referencedColumnName = "first_name", insertable = false, updatable = false)
#JoinColumn(name = "last_name", referencedColumnName = "last_name", insertable = false, updatable = false)
#NotFound(action=NotFoundAction.IGNORE)
private User parent;
The foreign key columns need different names than the primary key columns, e.g. like this (notice the 'parent' prefix in name):
#JoinColumn(name = "parent_id", referencedColumnName = "id", updatable = false, insertable = true)
#JoinColumn(name = "parent_firstname", referencedColumnName = "firstname", updatable = false, insertable = true)
#JoinColumn(name = "parent_lastname", referencedColumnName = "lastname", updatable = false, insertable = true)
#ManyToOne(fetch = FetchType.EAGER)
private UserEntity parent;
Additionally, the insertable value should be true, since otherwise no associations are persisted during the insert.
Be aware that a parent needs to be saved before a child can be associated. Since the parent fk is not updatable, is must be set on a newly created child before it is saved.
Feel free to have a look at this project containing the complete sample code:
Entity:
https://github.com/fladdimir/many-to-one-self-ref-composite-id/blob/master/src/main/java/org/demo/UserEntity.java
Integration-Test:
https://github.com/fladdimir/many-to-one-self-ref-composite-id/blob/master/src/test/java/org/demo/DemoApplicationTests.java
Also it is good practice to synchronize bidirectional associations:
https://vladmihalcea.com/jpa-hibernate-synchronize-bidirectional-entity-associations/
The sample entity could e.g. use some methods like these:
public void addChild(UserEntity child) {
child.parent = this; // sync owning side of the association
this.children.add(child);
}
public void setParent(UserEntity parent) {
parent.addChild(this);
}

HIbernate/JPA Annotation Join ManyToOne with multiple columns but with conditional OR

Let's say I have these Entities
Company,User,Project and Recommendation
But what I want to highlight is the Project and Recommendation table.
Below is the entity sample.
//Project entity
#Column(name = "id")
private String id;
#Column(name = "user_id")
private String userId;
#Column(name = "company_id", nullable = true)
private String companyId;
//Recommendation entity
#Column(name = "id")
private String id;
#Column(name = "user_id")
private String userId;
#Column(name = "company_id", nullable = true)
private String companyId;
#OneToMany(fetch = FetchType.LAZY)
#NotFound(action = NotFoundAction.IGNORE)
#JoinColumns({
#JoinColumn(name = "id", referencedColumnName = "user_id", nullable = true, insertable = false, updatable = false),
#JoinColumn(name = "id", referencedColumnName = "company_id", nullable = true, insertable = false, updatable = false)
})
private List<Project> projects;
Above tables are just illustration, sorry if that doesn't really make sense.
I want to join Project table inside Certification table.
They both are not directly related, so I need to join using these 2 columns, userId and companyId.
However, companyId is nullable. And whenever it is null, I still want to join the table only by userId.
What I want to achieve is probably along this line:
Select from Recommendation rec Join Project project
on rec.user_id = project.user_id and (rec.company_id = project.company_id OR rec.company_id is null)
Is it possible to use hibernate / JPA annotations to achieve this?
My project uses Hibernate 5 recently

ManyToMany Hibernate annotation

I have this relationship in my database:
And I want to be able to create an order, that contains more products (as well more instances of the same product). Nevertheless I am able to have just one row in the order_has_product table for every single order_id. Moreover, I tried to load the data via lazyloading, but it won't work and it makes the whole app to run really slowly. Here are definitions of the relationship in my entities:
OrderEntity:
#ManyToMany(fetch = FetchType.LAZY)
#Cascade({org.hibernate.annotations.CascadeType.ALL})
#JoinTable(name = "order_has_product",
joinColumns = {#JoinColumn(name = "order_id", nullable = false, updatable = false)},
inverseJoinColumns = {#JoinColumn(name = "product_id", nullable = false, updatable = false)})
private List<ProductEntity> products;
ProductEntity:
#ManyToMany(fetch = FetchType.EAGER, mappedBy = "products")
private List<OrderEntity> orders;
Any idea how to fix lazyloading and to make it possible to have more products in order?

custom constraint while updating Parent Entity Column in hibernate

For example I have two tables Employee and Department and I am using
#ManyToOne
#JoinColumn(name = "DEPT_ID", nullable = true, insertable = false, updatable = false)
private Department department;
in Employee.
Here I want to add one constraint that, whenever one of the column of Department is updated to some value then it should not get updated if it has child records in Employee.
Can I achieve this by using CascadeType?
Or is there any other way by which I can define custom constraint?
If your intention is to prohibit memory to database sync when Department is updated, then you're done as you have insertable=false, update=false:
#JoinColumn(name = "DEPT_ID", nullable = true, insertable = false, updatable = false)

Hibernate: delete records from association table with foreign keys

I'm new in hibernate. So, I don't know how to do this:
I have 3 tables:
Table Person:
#Entity
#Table(name = "ASD_PERSON")
public class AsdPerson implements Serializable {
#Id
#SequenceGenerator(name="seq_name", sequenceName="gen_id_value", allocationSize = 1)
#GeneratedValue(generator="seq_name")
#Column(name="F_PERSON_ID", nullable = false)
private Long fPersonId;
#OneToMany(mappedBy = "AsdPerson",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<AsdPersonEvent> asdPersonEventList;
... setters and getters ...
}
Table Event:
#Entity
#Table(name = "ASD_EVENT")
public class AsdEvent implements Serializable {
#Id
#SequenceGenerator(name="seq_name", sequenceName="gen_id_value", allocationSize = 1)
#GeneratedValue(generator="seq_name")
#Column(name="F_EVENT_ID", nullable = false)
private Long fEventId;
#OneToMany(mappedBy = "AsdEvent",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<AsdPersonEvent> asdPersonEventList;
... setters and getters ...
}
Table Person-Event:
#Entity
#Table(name = "ASD_PERSON_EVENT")
#IdClass(AsdPersonEventPK.class)
public class AsdPersonEvent implements Serializable {
#Id
#GenericGenerator(name = "generator", strategy = "foreign",
parameters = #Parameter(name = "property", value = "asdPerson"))
#GeneratedValue(generator = "generator")
#Column(name="F_PERSON_ID", nullable = false, insertable = false,
updatable = false)
private Long fPersonId;
#Id
#GenericGenerator(name = "generator", strategy = "foreign",
parameters = #Parameter(name = "property", value = "asdEvent"))
#GeneratedValue(generator = "generator")
#Column(name="F_EVENT_ID", nullable = false, insertable = false,
updatable = false)
private Long fEventId;
#ManyToOne
#JoinColumn(name = "F_PERSON_ID", insertable = false,
updatable = false)
private AsdPerson asdPerson;
#ManyToOne
#JoinColumn(name = "F_EVENT_ID", insertable = false,
updatable = false)
private AsdEvent asdEvent;
... setters and getters ...
}
Everything works perfectly (adding new records, creating new objects) except the case, when I try to delete associated records from Event table or Person table:
...
AsdEvent ev = getService().get(115); // get record from Event table by id = 115 (for example)
ev.getAsdPersonEventList().remove(1); // delete some existing records
getService().merge(ev);
...
After that I get error:
deleted object would be re-saved by
cascade (remove deleted object from
associations):
[database.AsdPersonEvent#database.AsdPersonEventPK#12908fc]
How to configure Hibernate with annotations or some other way to get rid of this error?
If you have a complex graph of persistent entities, I think you need to give up using orphanRemoval and remove your entities manually using em.remove().
orphanRemoval is designed for simple parent-child relationships, where child doesn't make sense without parent. If in your case child may have ohter relationships, perhaps it's not a good case for orphanRemoval.
Try once again by removing orphanRemoval = true

Categories