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.
Related
I decided to use single table inheritance which results in having multiple classes and I can't access the child's fields through a parent object in the view part of the application. So far I didn't find a nice solution how to deal with it in Thymeleaf. What does it mean?
Before I split my classes to use single table inheritance I could easily pass 1 object class that contained all the information needed to create or display the object but it had too many fields that would be null. With multiple classes thymeleaf doesn't really allow you to cast objects to a different type(and from what I understand it wouldn't be a good practice to do that in a view part of the application). So what is really the best way to deal with this problem?
I can come up with ideas like:
Create a DTO that contains the fields from all the classes and transform the objects to this class, it would be great in a create-view (POSTing DTO and then creating an object from it and adding to the database). But if I used this method for displaying information then it would mean casting each of the objects to a DTO class which kind of misses the point of single table inheritance in my opinion. I feel like this is too similar to going back to no inheritance at all.
Passing multiple objects or a parent object + a different object that would hold the rest of the information that the parent class doesn't hold. This also seems kind of weird.
Adding one method to a parent class per sub-class additional field and overwrite them in the sub-classes to return actual values while parent would return null. Not sure if this would fix the problem of creating the objects from a view though.
Let's assume this example with three simple classes where Person is a parent class and Client and Employee are children of it. I will skip getters, setters and constructors for simplicity.
Person main class that holds shared fields
#Entity
#Inheritance
#DiscriminatorColumn(name = "person_type", discriminatorType = DiscriminatorType.STRING)
public abstract class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
int personId;
int age;
String name;
}
Client class that extends person with additional field favouriteProduct
#Entity
#DiscriminatorValue(value= "CLIENT")
public class Client extends Person {
String favouriteProduct;
}
Employee class that extends person with additional fields salary and position.
#Entity
#DiscriminatorValue(value= "EMPLOYEE")
public class Employee extends Person {
String position;
int salary;
}
Given this simple structure I would like to create Employee and Client objects through a single form via a POST request and also display them together in a different view with their fields that are unique to each subclass. Problem is that I would need to pass an object that holds all the fields to the view to actually make it work which comes back to the problem and solutions that I came up with. Is there any correct way or best practice how to deal with this? I thought DTOs should rather scale down from full objects to objects with less fields.
Conclusion: if the answer isn't really that simple then what is really the use of single table inheritance in this case and why isn't it a good idea to just go back to 1 table implementation? I already know about polymorphic queries and it is a nice bonus but so far I can't really deal with the problem I explained above. Thanks in advance!
I don't know about Thymeleaf (sorry!), but I do know about object-oriented programming a bit. Leaving frameworks aside and talking from a pure OO perspective, parent classes know nothing about their children (inheritors). Only the opposite can be true, and that's if you use the appropriate access modifiers. Given that said, I believe you can not do what you want unless there is some ugly framework black magic going under the hood haha.
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?
Is it possible to annotate a class as #Embeddable or a property as #Embedded?
Sample code:
#Embeddable
class A{
...
}
class B{
...
}
#Entity
class Foo {
A a;
#Embedded B b;
}
When to prefer #Embedded and #Embeddable?
There are two primary uses for #Embedded/#Embeddable as far as I know:
First, and most important: Splitting up large entity classes. In the database world, a large table (one with many columns) is fine. Breaking up such a table might even make things worse, and be in collision with database design principles. In Java (or object oriented languages in general), on the other hand, a large class is a code smell. Here, we would like to split the classes, including entity classes, into smaller units. #Embedded/#Embeddable allows us to easily do this without having to split the database table.
Second, it allows for reuse of common mappings between entities. Say each table has a simple revision tracking, with two columns containing the username of the person who changed the row, and the time it happened. Then, one can make an #Embeddable entity covering these rows, and then reuse this across all entities by embedding it (rather than repeating the variables corresponding to these columns in each entity.)
If we have Person and Address that are two POJOs, You would not want to create another table for Address but you would want to embed the address within the person table. So Address is adding up value to the Person object but doesn't make any sense individually. In this case we may go with:
#Embeddable
public class Address{
}
#Entity
public class Person
{
#Embedded
private Address address;
}
You would use #Embeddable and #Embedded together. You mark your class as #Embeddable, which indicates that this class will not exist in the DB as a separate table. Now when you use #Embedded on the field itself.
The word embeddable and embedded gives you a big clue actually.
Embeddable = This class can be embedded in a class
Embedded = This class will now be embedded in your class as a field.
I guess if you annotate class as #Embeddable you don't need to annotate field as #Embedded. Also, if you annotate class as #Embeddable and you want to use it as primary key, you can use #Id only, but if it is not annotated as #Embeddable, you have to use #EmbeddedId on field to work as primary key.
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.
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?