I have a bidirectional many to one relationship. When I retrieve the parent object from the table, all the child objects should get retrieved but only the first one is getting retrieved
The parent looks like
#Entity
public class xyz{
#OneToMany(mappedBy="xyz",cascade=CascadeType.PERSIST,fetch=FetchType.EAGER)
private Set<zyx> zyxDO;}
The child class looks like
public class zyx{
#ManyToOne
#JoinColumn(name="id")
private xyz xyzDO;
}
Is there any annotation where I can retrieve all the rows of the underlying database
Maybe it is a typo, but the value of mappedBy should be the name of the attribute in the owning entity that points back to the inverse entity, in this case xyzDO.
And maybe because you are using a Set instead of a Collection could cause that only one child is retrieved (if they are identical).
What do you mean by retrieve all the rows of the underlying database? You retrieve only the children which parent's key set. Note also, that fetch eager can easily cause great performance issues, because children will be fetched always, even if you don't need them.
Ensure you set both sides of the relationships when adding/setting the relationship.
Related
I have an entity named Entity with a one to many relation with some children of the type Child set up by this:
#OneToMany(fetch=FetchType.LAZY, mappedBy = "child" ) private Set<Child> children;
I put fetch=FetchType.LAZY because I need it to be as quik as possible whenever I needn't know what children are.
Sometimes, instead I need to get them when I look for some Entity.
In those cases, according to the suggestions of these 1, 2, 3, 4 questions, I wrote something of the kind:
from Entity as ent left join fetch ent.children where /* some conditions */
the point is that I get conditions from another class, so I won't use Criteria, unless I find a way to transform a query object of the kind
getSession().createQuery("from Entity where /* some conditions */");
in a criteria. The problem is that I get the number of records given by the join, so one for each empty set of children and one for each Child.
What I need, is just the instance (or the list of instances, according to the fact that I call getResultList() on the list) of the Entity where the set is properly populated by the instance's children.
Actually this is a feature: Imagine you would fetch your Entity without it's children and later persist it again, Hibernate would delete all the children. Because it can not determine weather you did or did not delete them "yourself".
What you might want to try is fetching a Tuple (and in so doing only select the table columns you are interested in) instead of the whole entity. You can only access lazy fields (properly) within an active transaction.
So I have some entities that are used as the basis for a coordinate system, for the purpose of this post we'll call them A, B, C and D. Each of these entities has multiple #OneToMany relationships, and I want to cascade deletes. i.e. When some A is deleted, all entities in each of the #OneToMany relationships are deleted too. Fairly standard stuff.
However, I don't see the point in having these entities explicitly tracking these relationships when all I want to do is cascade a delete. I don't see the point in loading all these entities (potentially millions!) into memory each time a new entity is added to the #OneToMany relationship (i.e. using lazy loading only loads in when it's accessed, but it's of course accessed when a new entity in the relationship is added).
Let's add a little example:
#Entity
public class A {
#Id
private long id;
// ... other fields ...
#OneToMany
private Collection<SomeClass> collection;
}
#Entity
public class SomeClass {
#Id
private long id;
// ... other fields ...
#ManyToOne
A a;
#ManyToOne
B b;
// ... likewise for C, D ...
}
There can be multiple classes similar to SomeClass, and so multiple #OneToMany relationships in A (and B,C,D) that require tacking. This gets tedious FAST. Also, every time a new instance of SomeClass is added, I'd need to load the entire collection and this seems exceedingly inefficient (I'd pretty much end up with my entire database loaded into memory just to cascade a delete!!!).
How can I achieve what I want without modifying the underlying database (e.g. specfying ON DELETE CASCADE in the definition), surely the designers of JPA have considered such a use case? Maybe I'm incorrect that I'd need to load the entire collection when adding an entity to the relationship (if so, please explain why :) ).
A similar question was asked here: JPA: unidirectional many-to-one and cascading delete but it doesn't have a satisfactory solution, and it doesn't discuss whether or not the entire relationship gets loaded into memory.
To achieve a multi-level cascade without initializing all the entities you can only use a DB cascade.
There's no other way! That's why you couldn't find a satisfactory solution.
As for the:
Also, every time a new instance of SomeClass is added, I'd need to
load the entire collection and this seems exceedingly inefficient (I'd
pretty much end up with my entire database loaded into memory just to
cascade a delete!!!).
You need to understand the unidirectional Collections taxonomy:
Adding one element to a Set, requires the whole collection to be initializes to enforce the uniqueness Set contract.
a java.util.Collection or an unindexed List means you have a Bag, which are very inefficient in the unidirectional use case. For inverse collections they are fine, but that's out of your current context.
An indexed List (where the order is materialized in the database) is what you might be looking for:
#OrderColumn(name="orders_index")
public List<Order> getOrders() { return orders; }
The indexed list will use the index key for add/remove/update operations. As opposed to a Bag which simply deletes all elements and recreates the collection with the remaining elements, an index List will use the index key to only remove the elements that no longer belong to the List.
In JPA is it possible to create an #OnToOne relationship with just an idea and not embedding the class? For example:
#Entity public class Relationship {
#Id
#OneToOne
private Long parentId; // instead of "private User parent;"
#Id
#OneToOne
private Long childId; // instead of "private User child;"
int type;
...
I don't mind having a getter method with a lazy fetch but I don't need one and I'd prefer not to have to pull in complete parent objects to work with child objects. Also, I want to deserialize this to JSON using just the id and not the embedded object. I can do this by adding a getter that delegates to #getParent().getId() and putting a JsonIgnore on the #getParent() method (and the same for child) but I'd prefer to get the entity to look the way I want it to from the get go without adding this stuff. Possible and if so how?
Thanks!
No. How can an Object be related to a Number? This is an O-O language after all.
Labelling something as #OneToOne is semantically equivalent to a FK in the datastore. If you just omit #OneToOne and use a number then you have a numeric column in the datastore without a FK. So JPA allows both, but one gives the benefits of a FK, whereas with the other you just pass "numbers" around with no context of what they relate to
I have a #ManyToMany relationship between two entities. When I perform an update on the owning side, it appears that JPA deletes all the linked records from my database and re-inserts them. For me this is a problem because I have a MySQL trigger that fires before a record is deleted. Any ideas on how to get around this problem?
#Entity
public class User {
#Id
#Column(name="username")
private String username;
...
#ManyToMany
#JoinTable(name="groups", joinColumns=
#JoinColumn(name="username", referencedColumnName="username"),
inverseJoinColumns=#JoinColumn(name="groupname",
referencedColumnName="type_id"))
private List<UserType> types;
...
}
#Entity
public class UserType {
#Id
#Column(name="type_id")
private String id;
#ManyToMany(mappedBy="types")
private List<User> users;
...
}
Use Set instead of List solved the problem. But I have no idea why it works.
Another solution provided by Hibernate is to split the #ManyToMany association into two bidirectional #OneTo#Many relationships. See Hibernate 5.2 documentation for example.
If a bidirectional #OneToMany association performs better when
removing or changing the order of child elements, the #ManyToMany
relationship cannot benefit from such an optimization because the
foreign key side is not in control. To overcome this limitation, the
link table must be directly exposed and the #ManyToMany association
split into two bidirectional #OneToMany relationships.
Try this one:
1) change declaration to:
private List<UserType> types = new Vector<UserType>();
2) never call
user.setTypes(newTypesList)
3) only call
user.getTypes().add(...);
user.getTypes().remove(...);
Its probably related to this question. You have to ensure you have an appropriately defined hashCode an equals method in your mapped object so that Eclipselink can determine equality and thus determine that the existing objects map to existing objects in the DB. Otherwise it has no choice but to recreate the child objects every time.
Alternatively, I've read that this kind of join can only support efficient adding and removing of list items if you use an index column, but that's going to be EclipseLink specific, since the JPA annotations don't seem to support such a thing. I know there is an equivalent Hibernate annotation, but I don't know what it would be in Eclipselink, if such a thing exists.
It appears my problem was that I was not merging the entity.
Given the following:
#Entity
public class Parent implements Serializable {
#Id
private Long id;
// mapped ManyToOne below...
private List<Child> children = new ArrayList<Child>();
...
}
Is it a bad practice to have Parent.equals() and Parent.hashCode() use only id? I understand that Child.equals() and Child.hashCode() should use a immutable set of attributes for a "natural key" for them to be correctly managed by Parent. However, if Parent is always a top-level object (ie it's never the inverse side of any association), is there anything wrong with using only id?
Are there any unwanted effects that could manifest themselves by doing this? I am guessing that maybe if I do this, that when I add a child (or remove), Hibernate won't be able to tell that Parent has changed (and needs to be updated in DB)? In this case, should I use the children property for Parent.equals() and Parent.hashCode()?
I am asking because the Hibernate docs explicity say not to use the #Id property for a "natural key"...
The primary problem with using ID as a equals and hashCode basis is unpersisted objects. These objects presumably all start with the same ID and this can't properly be compared for equality. Even if you never put the objects in a collection, if they're exposed via an API and someone else can create instance of them and put them into a collection then you've opened yourself up to some nasty bugs.