I have the following JPA entity hierarchy:
Upon logging in to the application a user has an instance of UserAccount in session; then depending on the concrete type of the organization associated to that UserAccount (Admin, Business or Family), a different dashboard/screen is displayed to the user e.g. if the user is a Business, then the dashboard for that business is displayed.
My concern with that design is that I have to do a instanceof check each time a user logs in so that I know which type of dashboard to display. I could also avoid that instanceof check by having a property in UserAccount such as organizationType (which would take one of three values) but then there would be redundant information.
Is there a way to improve my design? If so how?
Be greedy and get both, without redundancy.
Depending on the inheritance strategy, you may already have the organizationType info and you can expose it for free.
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "DTYPE")
public abstract class AbstractOrganization implements Serializable
{
#Id
protected Long id;
#Column(name = "DTYPE", insertable = false, updatable = false)
protected String organizationType;
...
}
the same applies also to the JOINED strategy.
Do not implement the setOrganizationType method.
Since a discriminator is required for simulating hierarchies with tables (except TABLE_PER_CLASS strategy), there's no redundancy and JPA provider will handle this attribute for you.
Related
A legacy application persistence is based on JPA. There is an entity, People, mapped to the database table People.
Now a subset of all the rows in People needs some additional fields.
One possible solution is to use jpa inheritance and create a new entity, suppose EmployeedPeople, which extends People.
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class People {
...
#Entity(name = “EmployeedPeople”)
public class EmployeedPeople extends People {
Alternatively I can use unidirectional one to one relationship
#Entity(name = “EmployeedPeople”)
public class EmployeedPeople {
...
#OneToOne(optional = false)
private People commonPersonData;
I thought about a third way too: the new entity is based on a database view which joins People table with EmployeedData table.
This last approach is good for reading EmployeedPeople but impractical for inserting and updating because I have to work with different entities (People and EmployeedData).
Which criteria can help in choosing the strategy ?
Which are the pros and cons of each solutions ?
In internet I have already found the following guide which compares the inheritance strategies and this one on composition but my ideas are not clear yet.
Some JPA provider like Hibernate uses Proxy to handle lazy initialization. Consider the following example:
#Entity
public class Person {
#Id
private Long id;
#ManyToOne(fetch=FetchType.LAZY)
private House house;
}
#Entity
public class House {
#Id
private Long id;
#Embedded
private Address address;
}
When fetching a Person entity, its house property is set to a Proxy (lazy).
Person person = em.find(Person.class, 1);
House house = person.getHouse(); // Proxy
if (house == null)
System.out.println("has no house);
else
System.out.println("has a house");
If the person does not have a house, the person object has a Proxy of house (not null). The code above will print wrong message. Is this an issue for JPA proxy?
As a matter of fact, I'm surprised you're facing this issue. According to this question: Making a OneToOne-relation lazy, lazy optional many-to-one associations should work just fine; it is the one-to-one associations that cause problems. The issue here is that without enhancement, Hibernate cannot automagically turn the proxy into a null reference. Are you actually seeing this behavior in Hibernate?
In any case, you should be able to resolve the issue by enabling enhancement. This way, Hibernate is able to overwrite the getter method to return null if the initialized proxy does not represent a valid House. Not sure how the issue is resolved by other providers, though.
Following the principles of DDD and using Spring Data REST/HATEOAS what is the best way to manipulate entities in child collections.
For example:
#Entity
public class Topic{
#Id #GeneratedValue
private Long id;
private String title;
#OneToMany
private Set<Post> posts;
…
}
#Entity
public class Post{
#Id #GeneratedValue
private Long id;
private String title;
private String body;
#OneToMany
private Set<Comment> comment;
…
}
#Entity
public class Comment{
#Id #GeneratedValue
private Long id;
private String text;
}
Spring Data REST (SDR) inlines domain objects that don't have their own repositories when serializing to JSON.
{
"title" : "Spring",
"posts" : [{
"title": "Spring Boot 1.5.8",
"body": "blah",
"comments":[ {"text":"great!"} , {"text":"boo"},
{"text":"comment that should be removed by moderators"}]
}]
"_links" : {
"self" : {
"href" : "http://localhost:8080/topics/1"
}
}
}
The issue I have is that I am unable to get a handle on individual objects in a collection because SDR not only hides ids for all entities but also does not provide a 'self' link for inlined entities.
I don't want to simply PUT the whole aggregate because inline with DDD I want to handle changes of state via dedicated 'controller' resources, allowing the raising of event to trigger additional business logic. Consider adding/removing/updating a post comment in the example above.
I'm left with an number of options none of which I really like.
Reverse all my unidirectional relationships and create repositories for all the child entities, effectively abandoning the DDD aggregate design concept.
Move to bi-directional relationships, create repositories for all child entities and compose the aggregate using a Projection. The general advice from the internet (including SDR developer Oliver Gierke) is to avoid bi-directional relationships if at all possible due to performance considerations and having to manually manage the relationship.
Add a GUID or some other immutable unique identifier to the child entities. This feels wrong considering the whole point of HATEOAS is that the URI is the identifier. Even this breaks down when dealing with children of children.
I'm currently feeling inclined towards 2 as it seems to be the only workable option that allows me to retain the design principle.
Has anyone encountered and overcome a similar problem?
Edit:
I've come up with a possible solution:
Move to bi-directional relationships without creating repositories for child entities. This will give me the parents key so that I can compose a 'self' & other links using a ResourceProcessor e.g /topics/1/posts/add-post which I can handle via a RestController. This should work well enough at 1 level deep, it may have performance implications for deeper nesting e.g. /topics/1/posts/1/comments/add-comment as with JPA there's going to be a cost associated with doing the lookups to traverse the parent relationships. This would be done in tandem with #Alan Hay's solution to exposing Id's where there is no natural key in the entity.
This approach maintains DDD & HATEOAS at the cost of going against advice on bi-directional relationships.
Thoughts?
It is possible to add _links to resources that are not mapped through repositories. To add an action deleteComment, for instance, you should configure a #Bean like this:
#Bean
public ResourceProcessor<Resource<Comment>> commentProcessor() {
return new ResourceProcessor<Resource<Comment>>() {
#Override
public Resource<Comment> process(Resource<Comment> resource) {
resource.add(linkTo(methodOn(MyCustomController.class).deleteComment(resource.getContent().getId())).withRel("deleteComment"));
return resource;
}
};
}
You should get the link of the action on the Comment object inside the Post
Is it possible to create a basic FK relationship in JPA without involving the full entity target object?
As an example, imagine I have an entity:
#Entity(name = "Mechanic")
public class Mechanic {
#Id
private Long id;
//...
and a Car that I want to reference a Mechanic.id:
#Entity(name = "Car")
public class Car {
//...
#NotNull
private Long mechanic_id;
From an Object perspective, this would be a unidirectional, one to one relationship with the Car requiring a Mechanic.id and the Mechanic not needing any back reference to Car.
All I want out of this is to store the Mechanic.id ONLY. For the purposes of this question it is not useful to have a #OneToOne (or #OneToMany etc) relationship with the entity reference, I'm explicitly trying to avoid that but still retain the underlying integrity that a FK will provide.
JPA 2 and I'm using EclipseLink.
I suspect there's no perfect solution to this problem so least worst solution are more than welcome.
I'm implementing a dashboard using PrimeFaces and I would like to persist the model backing it (using JPA2). I've written my own implementation of DashboardModel and DashboardColumn with the necessary annotations and other fields I need. The model is shown below:
#Entity
public class DashboardSettings implements DashboardModel, Serializable{
#Id
private long id;
#OrderColumn( name="COLUMN_ORDER" )
private List<DashboardColumn> columns;
...a few other fields...
public DashboardSettings() {}
#Override
public void addColumn(DashboardColumn column) {
this.columns.add(column);
}
#Override
public List<DashboardColumn> getColumns() {
return columns;
}
...snip...
}
The problem is the columns field. I would like this field to be persisted into it's own table but because DashboardColumn is an interface (and from a third party so can't be changed) the field currently gets stored in a blob. If I change the type of the columns field to my own implementation (DashboardColumnSettings) which is marked with #Entity the addColumn method would cease to work correctly - it would have to do a type check and cast.
The type check and cast is not the end of the world as this code will only be consumed by our development team but it is a trip hazard. Is there any way to have the columns field persisted while at the same time leaving it as a DashboardColumn?
You can try to use targetEntity attribute, though I'm note sure it would be better than explicit cast:
#OrderColumn( name="COLUMN_ORDER" )
#OneToMany(targetEntity = DashboardColumnSettings.class)
private List<DashboardColumn> columns;
Depends on the JPA implementation (you don't mention which one); the JPA spec doesn't define support for interface fields, nor for Collections of interfaces. DataNucleus JPA certainly allows it, primarily because we support it for JDO also, being something that is part of the JDO spec.