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
Related
An Owner entity has a #ManyToOne - #OneToMany relationship with the teacher entity. When I annotate each like this
#Entity
public class Product {
...
#ManyToOne(cascade = MERGE)
private final Owner owner;
On the other side, in the Owner Class,
#Entity
public class Owner {
...
#OneToMany(mappedBy = "owner", cascade = MERGE)
private final List<Product> products;
What happens now is that "owner" in the line mappedBy = "owner" turns red. Hovering over it, I get the error that the owner attribute cannot be found.
The error: Cannot find inverse attribute
The solution was simply to remove the final keyword in the attribute owner in the Product class.
It becomes private Owner owner and the error disappears. I don't understand why adding the keyword final causes this problem.
Why does this happen?
Is there a workaround? Can I still make the owner attribute final?
The main idea from the getgo was to make the product class immutable. While this is a challenge, I've managed to find a workaround for most things, but I didn't know how to fix this problem.
JPA does not support immutability. A JPA entity does require a default constructor and getters and setters for properties.
And the fields must not be final.
Technically it would be possible to implement an ORM that ignores final attributes but why should it?
The keyword final says: This gets assigned a value at construction time and never changes after that. This is just not true for JPA entities which get constructed via no-args-constructor and then populated in second step.
If you are looking for an ORM that has better support for immutable classes (constructor with arguments, "wither" methods) you might want to check out Spring Data JDBC.
Full disclosure: I'm Spring Data developer working on both Spring Data JPA and Spring Data JDBC.
I think you have understood immutability concept wrong. Immutability is a concept being forced by the Java language. For example String class is immutable because of the security, caching etc. But in your case Product is an entity class and if you save it in a persistent layer, it is already unique on it's own. So even if you make the Product class immutable, how are you going to keep that consistency during two application loads?. If you are trying to make a Product having owned by only one owner, then do a db check rather than trying to make it immutable in memory.
How does the Embedded annotation affect the database?
How will SQL queries need to change?
What's the typical usecase for using the annotation?
How does Embedded annotation affect the database?
It does not affect it at all. On ORM provider layer all fields from embedded entity are merged with parent entity and treated the same as if they were declared there all the time. In other words it works as if you would literally copy all the fields, getters and setters into the entity that contains embedded object.
How will SQL queries need to change?
They won't. You don't need to change anything. See above.
What's the typical case for using the annotation annotation?
Sometimes you have a huge table with several columns (especially with legacy databases). However some columns are logically tied to each other (like street, city and phone number in CUSTOMER table). When you don't want to create an object with all the fields, you create an embedded Address object. This way you logically group address columns into an object instead of having equally huge POJO with a flat list of fields.
Using embedded objects is considered a good practice, especially when strong 1-1 relationship is discovered.
extending the answer of #Tomasz Nurkiewicz Embedded objects are useful to mapping a table's with a composite primary key whit help of the annotation #EmbenddedId
What's the typical usecase for using the annotation?
This is typically to represent a composite primary key as an embeddable class:
#Entity
public class Project {
#EmbeddedId ProjectId id;
:
}
#Embeddable
Class ProjectId {
int departmentId;
long projectId;
}
The primary key fields are defined in an embeddable class. The entity contains a single primary key field that is annotated with #EmbeddedId and contains an instance of that embeddable class. When using this form a separate ID class is not defined because the embeddable class itself can represent complete primary key values.
How does the Embedded annotation affect the database?
It does not. Use this annotation to represent a composite primary key.
How will SQL queries need to change?
They won't.
Like Tomasz said - that's the one goal - the other - you can "snaphot" the state of other related entity inside your table.
F.e.
#Embeddable public class Company {
String name;
String streetName;
String city;
}
#Entity public class Invoice {
#Embedded
#AttributeOverrides({
#AttributeOverride(name="name", column=#Column(name="name")),
#AttributeOverride(name="streetName", column=#Column(name="streetName")),
#AttributeOverride(name="city", column=#Column(name="city")),
})
Company seller;
#Embedded
#AttributeOverrides({
#AttributeOverride(name="name", column=#Column(name="name")),
#AttributeOverride(name="streetName", column=#Column(name="streetName")),
#AttributeOverride(name="city", column=#Column(name="city")),
})
Company customer;
}
in this example - without embedded and #AttributeOverrides any change in future of Company customer will change the data in Invoice - which is a bug - the invoice was generated for the company with old data.
It's good explained here: :)
Java - JPA #Basic and #Embedded annotations
It doesn't always have to be the ID of the class. In Domain Driven Design, you can create a component out of some of the properties of an object, e.g. in this example http://yaarunmulle.com/hibernate/hibernate-example/hibernate-mapping-component-using-annotations-1.html a student has an address component.
The Address property of Student is annotated with #Embedded to point to the Address class component.
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.
Put another way: How do you model/map a heavily reused child class/table to many different parent entities?
I have several entity types each being persisted into its own table:
class A --> table A
class B --> table B
....
Now I need to make each of these classes the parent of a 1:M unidirectional child collection. The collection is a history of approvals the entity has gained over time. The Child domain class is called "ApprovalItem". The Approval class is exactly the same for all types of parents.
What is the best way to map this? If I create a single table to hold all ApprovalItems, then I can't enforce a FK relation to the PK of the entity and/or I am left with a bad database design.
On the other hand, I could create an ApprovalIems table for each entity type (e.g. A_ApprovalItems, B_ApprovalItems, etc.). This seems like a good schema on the database side, but then it seems I need to create a separate domain classes in Java for each entity approval (e.g. AAprrovalItem class, BApprovalItem class, etc.). This seems like a lot of hassle and complexity to create so many new classes in Java that do nothing other than allow me to put in different JPA mapping annotations.
Is there a mapping technique in Hibernate that will allow me to have one class in Java map to several different tables depending on who the parent owner of the collection is?
I could create an ApprovalItem table for each entity type (e.g. A_ApprovalItem, B_ApprovalItem, etc.). This seems like a good schema on the database side
But
It seems i need to create a separate domain classes in Java for each entity approval (e.g. AAprrovalItem class, BApprovalItem class, etc.).
You do not need it. you can create a single ApprovalItem class and create a #OneToMany relationship between your parent classes and your ApprovalItem. Hibernate takes care to create a linked table for each relationship.
#Entity
public class ClassA {
#Id
#GeneratedValue
private Integer id;
// Hibernate will create CLASSA_APPROVALITEM to link both class
#OneToMany
private List<ApprovalItem> approvalItemList;
}
#Entity
public class ClassB {
#Id
#GeneratedValue
private Integer id;
// Hibernate will create CLASSB_APPROVALITEM to link both class
#OneToMany
private List<ApprovalItem> approvalItemList;
}
And your ApprovalItem class
#Entity
public class ApprovalItem {
#Id
#GeneratedValue
private Integer id;
// Nothing else
}
But Let's see what Java Persistence with Hibernate book talks about it
You may have shared references to the Bid objects. As suggested earlier, a User may have a collection of references to the Bid instances they made. You can’t delete an item and all its bids without removing these references first. You may get an exception if you try to commit this transaction, because a foreign key constraint may be violated.
So keep it in mind when dealing with shared references.
In order to see how the target schema looks like, you can use the following
AnnotationConfiguration configuration = new AnnotationConfiguration();
configuration
.addAnnotatedClass(ClassA.class)
.addAnnotatedClass(ClassB.class)
.addAnnotatedClass(ApprovalItem.class)
.setProperty(Environment.USER, <TYPE_YOUR_USER>)
.setProperty(Environment.PASS, <TYPE_YOUR_PASSWORD>)
.setProperty(Environment.URL, <TYPE_YOUR_URL>)
.setProperty(Environment.DIALECT, <TYPE_YOUR_DIALECT>)
.setProperty(Environment.DRIVER, <TYPE_YOUR_DRIVER>);
SchemaExport schema = new SchemaExport(configuration);
schema.setOutputFile("schema.sql");
schema.create(<DO_YOU_WANT_TO_PRINT_TO_THE_CONSOLE>, <DO_YOU_WANT_TO_EXPORT_THE_SCRIPT_TO_THE_DATABASE>);
It will generate a file called schema.sql, which contains your target schema
regards,
Chapter 8. Inheritance Mapping of Hibernate Documentation might help.
Otherwise, I see no problem having multiple ApprovalItem derived class that "do nothing", like you say, since it does differentiate the Approval, it's like having a type of approval. Seeing your model like so, I would recommend using multiple classes, even if they only inherit from your base ApprovalItem class.
Have I well understood your question or am I missing something else more subtle?
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.