Implementing equals/hashCode using a referenced ManyToOne entity - java

Assume we have following JPA Entities:
class Parent {
#Id
private Long id;
}
class Child {
#Id
private Long id;
#Column
private String name;
#ManyToOne(fetch = FetchType.LAZY)
private Parent parent;
}
Let's assume a Child can uniquely be identified by its name on the Parent (combination of both). So, Parent and name can be considered as the business key of a Child.
I am unsure now what the best approach would be to implement equals (and hashCode) on the class Child.
Reference the id of the application
Since the Application proxy will be loaded and its id will be set on the proxy so the Application entity itself would not be initialized:
public boolean equals (Object o) {
//null check, instanceof check ...
return new EqualsBuilder().append(getName(), other.getName())
.append(getParent().getId(), other.getParent().getId())
.isEquals();
}
This will do the trick but I see some downsides as well. First (minor), an extra not null check on the parent would probably be advisable which makes your equals methods less compound.
Next (less minor), This would required hibernate to access the properties rather than the fields; so, I would need to set the annotations on the getters instead of on the fields. This is something I can live with personally but the habit in the current project is to put the annotations on field level.
Don't use the referenced entity for evaluating equality
Ok, but then I need something else. I don't want to use the id of the Child (bad practice) which leaves me with only 1 option: using a separate property for this, like a UUID. I have nothing against the use of UUID's but of course only if there is no other option available.
My questions are:
Did I miss an option?
What, in your opinion, would be the advised way of doing this?

Another possibility would be to add another field containing the foreign key to the parent which can then be used in the equals and hashCode methods without fetching the referenced entity:
#Column(name="parent_id", insertable=false, updatable=false)
private String parentId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="parent_id")
private Parent parent;

If you can get hold of the EntityManagerFactory (and if you can get hold of the EntityManager, EntityManager.getEntityManagerFactory() is one way to do it), another way to get the parent's ID is with:
emf.getPersistenceUnitUtil().getIdentifier(parent);
You'd still need a null check, though.

Related

Should equals be burdened by the business logic of the application?

Let's say we have such classes in the Java project:
#Entity
class Person {
#Id
String internalId;
#OneToMany
Set<Profession> profession;
}
#Entity
class Profession {
#Id
String id;
String professionName;
Integer yearsOfPractise;
}
In the business logic the professionName has to be unique per Person.
Is it correct to #override the equals with taking into the account only the professionName field and ingoring the others?
On the one hand such the equals can be handy if this class is handled from the business logic perspective. But such equals can be completely wrong and unhandy in cases when this class will have to be handled from some different perspective.
How to decide it?
Of course, this way you are using a business id, instead of the one that is probably generated by the jpa vendor and as a result, entities, that are manages are equal to the same that aren't.
For example if we create an entity, where the id is generated by the database and save it, the following gives no error:
Entity entity = new Entity();
Entity savedEntity = entityRepository.save(entity); // CrudReporitory
assertFalse(entity.equals(savedEntity));
In most cases it's not what we want. For more details I recommend this article.
You can overide the equals according to your business logic. In my case, I have excluded id.You can modify which fields are used with the lombok library:
https://projectlombok.org/features/EqualsAndHashCode
For Example:
#EqualsAndHashCode(exclude = "id")
public class Foo {
private Integer id;
}
Since, there are two cases:
comparing two entities by equality (content)
comparing two entities by an identifier
You should not override equals to do either or. This would be confusing. Instead use a dedicated function for each. This way you/or anyone else reading the code can choose the correct one and this choice will be obvious to the reader.

JPA Inheritance mapping - Making a field optional in 1 subclass, mandatory in another

I have a entity in the application I am working for that has two versions.
I have mapped the entity using JPA inheritance mapping so that there are now two classes, let's call them Contract and OtherContract. They both have a couple of shared fields, defined in BaseContract. Both classes inherit from that base class.
The problem now is that of those shared fields, some should be mandatory (as in have a not null constraint in the database) in the "Contract" class but optional in "OtherContract".
What I could do is duplicate all of the fields from the shared class in both classes and modify the annotations accordingly but that seems hard to manage.
(like this:)
public class Contract extends BaseContract {
#Column(nullable = true)
private String name;
}
public class OtherContract extends BaseContract {
#Column(nullable = false)
private String name;
}
I could also make all the fields non-mandatory and add the validation in my domain layer (which I'll do anyway). I like this a little better but the database tables will have all the fields optional which I don't like.
The inheritance type I will probably have to use is TABLE_PER_CLASS
Does anyone know a solution without these drawbacks?

Entity doesn't have fields required for Form Object

I have Entity:
public class User {
private Long id;
private String name;
private String lastName;
private String email;
private String password;
// getters and setters
}
I would like to use it as a Form Backing Object in presentation layer, but it doesn't have fields that I need. In this case I need repeatedPassword field.
What is the best approach to this problem without modifying entity class?
Should I extend this entity class and add needed fields?
Should I create new class which has a field private User user; with getter and setter?
Should I copy/paste this class and then add needed fields?
Three different solutions:
The usual way of dealing with a situation where the input fields on a form don't match up with an entity is to use a Command object (this is what Sotirios was advocating in the comments). Making a separate object for this that is not an entity is much less confusing than extending the entity to add something unrelated to persistence.
It be argued in this case there's no need to pass the repeatedPassword field back to the server, the validation could be done entirely on the client, and the input field doesn't need to be bound to a Java pojo at all.
If you really want to pass the repeatedPassword back to the server (so you can do all your validation on the server-- although the repeated password is more of a user convenience than real validation), then you could add the repeatedPassword field to the User entity with a #Transient declaration.

Hibernate : Difference between # Embedded annotation technique and #OneToOne annotation Technique

What is the difference between #Embedded annotation technique and #OneToOne annotation technique because in Embedded the java class contain "Has a" relationship in class and with the help of #Embedded annotation we persist the has a object in database. and in OneToOne relationship we also persist the has a object in database.
#OneToOne is for mapping two DB tables that are related with a one to one relationship. For example a Customer might always have one record in a Name table.
Alternatively if those name fields are on the Customer table (not in a separate table) then you might want an #embedded. On the face of it you could just add the name fields as standard attributes to the Customer entity but it can be useful if those same columns appear on multiple tables (for example you might have the name columns on a Supplier table).
Its the difference between composition and aggregation. #Embedded objects are always managed within the lifecycle of their parents. If the parent is updated or deleted, they are updated or deleted as well. #OneToOne objects may mimic composition via the cascadeType option of their #Join annotation, but by default they are aggregated, aka their lifecycle is separate from that of their parent objects.
#Embedded is used with Value Objects (Objects which have a meaning only when attached to an Object) whereas one to one mapping is between two objects having their own existence and meaning.
For e.g.
Value Object and #Embedded: If we have a User class and this class has an address Object in it, it can be considered as a value object as the address alone does not have any significance until unless associated with a user. Here address object can be annotated with #Embedded.
One to One mapping and #OneToOne: If we have a User class and this class has a 'Father' Object or a 'Mother' object, we would want to annotate the 'Father' or 'Mother' instance as #OneToOne as 'Father' or 'Mother' have their own meaning and existence and are not Value objects to User class.
A closely related difference is between #OneToMany and #ElementCollection. Both are used to save instance variables of Collection type in Java class. The difference being, #ElementCollection is to be used when the elements of Collection being saved are Value Objects whereas #OneToMany is used when the elments and object have well defined meaning and existence.
Use #OneToOne, only if fields can be reused. Otherwise, go for #Embeddable.
A quote from Beginning Hibernte, 3rd Edition:
There is nothing intrinsically wrong with mapping a one-to-one association between two entities where one is not
a component of (i.e., embedded into) the other. The relationship is often somewhat suspect, however. You should
give some thought to using the embedded technique described previously before using the #OneToOne annotation.
#Embeddable:
If the fields in an entity (X) are contained within the same table as another entity (Y), then entity X is called "component" in hibernate terms or "embedded" in JPA terms. In any case, JPA or hibernate do not allow to use 2nd table to store such embedded entities.
Generally, we think of normalizing a table when data is being reused by more than one table. Example: A Customer (id, name, street, city, pin, landmark) can be normalized into Customer(id, name) and CustomerAddress(cust_id, street, city, pin, landmark). In this case, we can reuse CustomerAddress by linking the same using cust_id with other tables. But if this reuse is not required in your application, then we can just keep all columns in one table.
So, a thumb rule is,
If reuse -> #OneToOne,
If no reuse -> #Embeddable
#Embedded 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.
#OneToOne is for mapping two DB tables that are related with a one to one relationship. #Id will be the primary key.

Read Hibernate entity identity value

Does Hibernate have an API for reading the value of an entity's identity field? In my case, this would be the Serializable value returned by the field annotated with #Id. For example, suppose I had a Person entity:
class Person {
#Id private long id;
// ... other fields, getters/setters, etc ...
}
Person p = new Person();
p.setId(42L);
Hibernate.unknownFunction(p); // returns 42L
Sure I could read the annotations to find the #Id field myself, but this seems like something that might be built in.
session.getIdentifier(object)
Return the identifier value of the given entity as associated with this session. An exception is thrown if the given entity instance is transient or detached in relation to this session.
The object needs to have an ID, and to be associated with the current session, otherwise an exception is thrown. But that is logical, I think.
Well, if you need a method that return id in arbitrary classes, design a interface to satisfy this. for example:
public interface IdHolder {
Integer getId();
}
With such interface, you could make some utility methods to retrive id from arbitrary classes.
The cglib is a robust but a bit of tricky way to do it.
I can't say 100% no - but I really doubt it since not all Entities are annotated with #Id; there are other variants that can be used such as #EmbeddedId. Given this, can't you just use reflection to get at your id value?

Categories

Resources