To illustrate my question consider the following example:
#Entity
public class Box implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#OneToMany //No cascade
private List<Item> items;
.
.
.
}
Above we have a Box which has a one-to-many association with Item
Now say you grab a Box object and start filling it with Items and try to persist it. It will tell you that you cannot do this because you have some non-transient nested objects with no cascade (or something like that).
In this situation, where you only want an association (with no persistence), but you want to use those fields while the object is alive, what do you do when you want to persist it?
Do you null the list of Item? Do you annotate it with #Transient?
That is my question. Thanks!
If your Item object is not an database entity you should annotate the collection as #Transient. If the Item object is mapped into the database you should use the #OneToMany annotation so this collection will be read from the database. To prevent this collection from being stored when you save the Box object you can add the #JoinColumn annotation and set the insertable and updatabble attribute to false:
#OneToMany
#JoinColumn((name="BOX_ID", insertable=false, updatable=false)
private List<Item> items;
Related
We have in our spring boot (1.5.6) app a classical bi-directional OneToMany hierarchy in our entities, e.g. an Order has many Item.
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(mappedBy = "order", )
#JsonManagedReference
private Set<Item> items = new HashSet<>();
// getters and setters
}
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JsonBackReference
private Order order = new HashSet<>();
// getters and setters
}
In our JavaScript-view, which uses rest-controllers to fetch the data, sometimes the Order and sometimes the Items is the root object. Let's say we have somekind of "Show Order" and another "Show Item" view.
So, if Order is the root, we want to know also its children (items) and if an Item is the root, we also want to know its parent order.
The serialization obviously would generate an infinite recursion, so we would normally use #JsonManagedReference and #JsonBackReference here.
However, this removes the back-reference (so we have a one-directional serialization here...). We also tried to use JsonIdentityInfo - which does not work, because elasticsearch has some problems during the deserialization and we also have some cross-references which will be also replaced by the ids and messes everything up...
Long story short, our idea is now to have somekind of "depth-break":
When the first serialized object is an Order, then its items-property should be fully serialized. But for each Item the back-reference to order should not be serialized (one can say here "the depth of order is 2").
When the first serialized object is an Item then its back-reference order is serialized, but the second managed-refrence to items will be ignored.
We tried also JsonView for this, but we cannot dynamically set this value.
Anyone who solved that or has an approach what we can use for this?
Instead of #JsonManagedReference and #JsonBackReference you can use #JsonIgnoreProperties annotation to suppress serialization of nested properties:
public class Item {
//...
#JsonIgnoreProperties("items")
#ManyToOne
private Order order = new HashSet<>();
//...
}
I have an entity with a field updatedUser which keeps track of the user who updated the row values.
When the entity is created this field is null but it should be set when a change is made to the entity and merge is used.
Is there some way, through java, to fill this value only when the entity has been updated? IE: should not be changed if it is created or retrieve from db.
#Entity
#Table(name="employees", uniqueConstraints= {
#UniqueConstraint(columnNames="idEmployees"),
#UniqueConstraint(columnNames="idCardNumber"),
#UniqueConstraint(columnNames="niNumber")
})
public class Employee {
#Id
#GeneratedValue
#Column(unique=true, nullable=false, updatable=false)
private int idEmployees;
//other class variables
#ManyToOne(cascade=CascadeType.PERSIST, fetch=FetchType.LAZY)
#JoinColumn(name="updatedEmployeeId")
private Employee updatedEmployee;
//constructors, getters and setters
}
Updating a value is possbile by using the javax.persistence.PreUpdate annotation. But there is no way to inject the current user. Maybe it is possible to read the user from ThreadLocal and then set the user, but that is not a really clean solution as it must be set before when entering your business code or so ..
I have two entities, let's say
Person.java:
#Entity
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = AUTO)
private long id;
#OneToMany(mappedBy = "personData", cascade = CascadeType.PERSIST)
private List<SkillsData> skillsData;
// ...
}
SkillsData.java
#Entity
#Table(name = "SkillsData")
public class SkillsData implements Serializable {
#Id
#GeneratedValue(strategy = AUTO)
private long id;
#JoinColumn(name = "PERSONID")
#ManyToOne(cascade = REMOVE)
private Person personData;
// ...
}
When I create a person, add a list of type SkillsData to it's skillsData field and persist it everything works with no exceptions thrown, but when I browse the database directly in the SkillsData table the field PERSONID is not populated and because of that the skills added can't be referenced to the right person.
I'm trying to fix this problem for quite some time and I'll be thankful for any help.
The problem might be in the fact that you're not setting SkillsData.personData before persisting leaving it null.
You must set it cause adding SkillsData to the Person.skillsData list is not enough since you declared this side of relationship as inverse(mappedBy attribute).
Therefore it is the SkillsData.personData non-inverse side who is responsible for establishing this relationship.
I'm mapping a Filter ---< FilterColumn where Filter presents cardinality one and FilterColumn N. So the mapped classes are:
#Entity
public class Filter implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String name;
private String caption;
#OneToMany(cascade = CascadeType.MERGE, targetEntity = FilterColumn.class)
private Set<FilterColumn> columns;
// setters and getters
}
#Entity
public class FilterColumn implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private FilterColumnId id;
private String caption;
// getters and setters
#Embeddable
public static class FilterColumnId implements Serializable {
private static final long serialVersionUID = 1L;
#ManyToOne
private Filter filter;
#Column
private String name;
// getters and setters
}
}
But when I start the application with drop-create instruction the following 3 tables are created:
Filter PK(name)
FilterColumn PK(filter_name, name)
Filter_FilterColumn PK(filter_filter_name, filterColumn_filter_name, filterColumn_name)
What I really want is just two tables like:
Filter PK(name)
Filter_Column PK(name, filter_name)
Why do I receive this result? Is there something wrong with my mapping? What should I change?
Thanks in advance.
I think you need a mappedBy on the #OneToMany. Without that, the mapper doesn't know that it can look at the filtercolumn table to find the entities associated with a Filter, so it generates the filter_filtercolumn table.
Not sure off the top of my head how you to a mappedBy with a composite key. Given that you're using an #EmbeddedId, i think it's simply mappedBy = "id".
Can you use a #ManyToOne in a key class like that? Is that a Hibernate extension over and above the JPA spec? Wouldn't you normally need a #MapsId in there somewhere?
Try adding a #JoinColumn annotation on the Filter member of your composite id. The actual column would be whatever the id of the of the Filter table is (or just leave it without a name if you let hibernate generate it all).
Let me know if this works as I had a similar problem and solved it using the above so I do know it's possible. The only other thing mine has is a #ForeignKey annotation but I think hibernate will take care of that for you -- I just did mine because I wanted to stick to a naming convention.
I am using JPA (Hibernate) with the following entity class with one one-to-many relationship.
When I add elements to the list, and then persist the Organization entity, it adds the new elements to the proyects table, but when I remove elements from the list, nothing happens when persist (or merge), and I would like these elements to be removed from the database.
I tried also orphanRemoval=true in the OneToMany annotation, but it doesn't work.
#Entity
public class Organization {
#Id
#GeneratedValue
public long internalId;
#Basic
#Column(nullable = false, length = 100)
private String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "organization")
private List<Proyect> proyects;
// Getters and Setters
}
You need to set Proyect.organization to null and update that entity, since this property is responsible for the database entry (Proyect is the owning side in this case ).