Play Framework - How to inherit from superclass? - java

I have a User class, which extends Model, and two classes that I want to extend the User class.
User.java:
#Entity
#Table(name = "users")
public class User extends Model implements RoleHolder {
private static final long serialVersionUID = 1L;
#Id
public Long id;
...
Driver.java:
public class Driver extends User {
...
Customer.java:
public class Customer extends User {
...
Edit
All three entities need to be directly accessed. To say it another way, I have Users, Customers, and Drivers; Customers and Drivers just happen to share all of the properties of a User. Therefore, I need to have a valid User entity as well as Customer and Driver.
I need to be able to get a list of all Users (including Customers and Drivers).
I haven't been able to figure out how to make this work using ebean in Play. How can I do this?

To keep the User table concrete, you can use the #Inheritance annotation. See Play Framework 2 Ebean and InheritanceType as JOINED for a discussion about that.
Also possible is to manually join auxiliar tables for Drivers and Customers using #OneToOne.
Using #OneToOne would also be favor composition over inheritance, which is considered a good practice.

This might be an use case for the MappedSuperClass annotation. See http://docs.oracle.com/javaee/5/api/javax/persistence/MappedSuperclass.html for documentation. Presumably, this is suppoerted by Ebean, although there's a lack of documentation about it.

Related

Java ORM vs multiple entities

I have a class Health Check - as part of the class I record how many parasites are seen (enum NONE, SOME, MANY) and also the location of the parasites (enum HEAD, FEET, BODY).
Two ways this could be done:
METHOD 1
Health Check
#Entity
public class HealthCheck {
#Id
#GeneratedValue(strategy = AUTO)
private Long id;
private Parasite parasite;
Parasite
public class Parasite {
private BodyLocation bodyLocation;
private Coverage coverage;
}
Or I could have:
METHOD 2
#Entity
public class HealthCheck {
#Id
#GeneratedValue(strategy = AUTO)
private Long id;
private ParasiteNumber parasiteNumber;
private ParasiteLocation parasiteLocation;
Would method 1 require #Entity on parasite class and a entry in the table for each Health Check and a #OneToOne annotation?
Note Parasite class is not used anywhere else. Its only a part of a Health Check.
Which way is correct?
Generally speaking, yes. In ORM (aka JPA or Hibernate), you are building a graph of objects that represent things in your database. Anything that one #Entity touches is also an #Entity because it's a graph.
Whether it's a #OneToOne or a #ManyToOne, etc, depends on the nature of your data model. But, keep in mind, those connections can also be #Lazy, so they are not loaded until they are needed.
Because of #Lazy, method 2 might be preferred, idk. I assume ParasiteLocation and ParasiteNumber is some sort of join-table. If that's the case, you could load a HealthCheck with its PL and PN, but those objects could be Lazy to Parasite.
I don't think there is a one-size-fits-all answer to your question. It very much depends. But good news, ORM is flexible to cover any/all scenario you might have.
If Parasite is only used in HealthCheck class,which can be seen as an association.
Association means that the existence of child class is dependent on the existence of the parent so it has no independent lifecycle ,thus you can either declare the attributes directly in HealthCheck as you did in your second example ,or you can declare them in Parasite class and then make it Embeddable inside the HealthCheck class,e.g:
/*To embed a class inside in Entity you must declare it Embeddable via the JPA
annotation #Embeddable */
#Embeddable
public class Parasite {
#Column(name="body_location")
private BodyLocation bodyLocation;
#Column(name="coverage")
private Coverage coverage;
}
#Entity
public class HealthCheck {
#Id
#GeneratedValue(strategy = AUTO)
private Long id;
#Embedded
private Parasite parasite;
}
Here your HealthCheck db table will have the attributes specified in the Parasite class,and note that Parasite table won't be created since it is Embedded and not an Entity (#Entity).
Hope this helps!

Choosing Inheritance Strategy - Hibernate

if this question was aksed here, i surely couldnt find it, or it didnt particulary help me.
i've read some tutorials and some questions for Inheritance Mapping, which couldnt quitely solve my questions.
Say i have an abstract class :
User
And 3 more other subclasses :
UserA, UserB, UserC
those all extend User.
Every Subclass has its own table, Superclass User, meanwhile, doesn't.
In my other class Website i have a ArrayList, or should i say Collections, of Users.
The list should fetch all users of the Website.
Which strategy should i use ? I thought of MappedSuperclass, but since in my Website class the List is of User type, so am not sure what to do here.
Thanks for any help!
With JPA the Java implementation always depends on you own preferences and requirements, sometimes it is the matter of a choice.
Yes, #MappedSuperclass will do.
You can have every child with unidirectional relationship to Website. Then you gonna have Website object inside your User class (with a bunch of annotations), which will map to a database as foreign_key field (presume you are using SQL storage and 'Repositories' DAO abstraction from JPA).
It is not necessary to store a collection of users inside Website class. Just think if you really need it - it can be a mess to support consistency.
But there are cases where you need bidirectional relationship. When you store objects in memory (for caching purposes for example) you'll probably need to have this collection. In this case why not to have 'User' collection? You will fetch data through dedicated repositories(or even if you're not using those, any other way will be using 'User' tables with foreign_key, not the 'Website' table) anyway.
So, for example with the use of Spring Data JPA you can define a unidirectional relationship in a superclass and use 'repositories' next way(and bidirectional example you can find anywhere in the internet, so I am not providing it):
#Entity
public class SuperUser extends User {
...
}
#Entity
public class BasicUser extends User {
...
}
#MappedSuperclass
public abstract class User implements Serializable {
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "website_uuid", nullable = false)
protected Website website;
...
}
#Entity
public class Website implements Serializable {
...
}
#Repository
public interface SuperUserRepository extends CrudRepository<SuperUser, Long> {
Iterable<SuperUser> findByWebsite(Website website);
}
#Repository
public interface BasicUserRepository extends CrudRepository<BasicUser, Long> {
Iterable<BasicUser> findByWebsite(Website website);
}
What you are asking for seems a typical "Table-per-concrete-class" inheritance strategy. https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#entity-inheritance-table-per-class
In older version of the user guide, it has mentioned that separate table will be mapped for each non-abstract classes. In the latest document the "non-abstract" part is not mentioned but I believe it still works similarly.
So it looks something like:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
abstract class User {...}
#Entity
class UserA extends User {...}
#Entity
class UserB extends User {...}
#Entity
class UserC extends User {...}
But you should be aware of this inheritance strategy usually gives inefficient query as internally it is using union.

Persisting third-party classes with no ID's

Say I have the following Java class, which is owned by a vendor so I can't change it:
public class Entry {
private String user;
private String city;
// ...
// About 10 other fields
// ...
// Getters, setters, etc.
}
I would like to persist it to a table, using JPA 2.0 (OpenJPA implementation). I cannot annotate this class (as it is not mine), so I'm using orm.xml to do that.
I'm creating a table containing a column per field, plus another column called ID. Then, I'm creating a sequence for it.
My question is: is it at all possible to tell JPA that the ID that I would like to use for this entity doesn't even exist as a member attribute in the Entry class? How do I go about creating a JPA entity that will allow me to persist instances of this class?
EDIT
I am aware of the strategy of extending the class and adding an ID property it. However, I'm looking for a solution that doesn't involve extending this class, because I need this solution to also be applicable for the case when it's not only one class that I have to persist, but a collection of interlinked classes - none of which has any ID property. In such a scenario, extending doesn't work out.
Eventually, I ended up doing the following:
public class EntryWrapper {
#Id
private long id;
#Embedded
private Entry entry;
}
So, I am indeed wrapping the entity but differently from the way that had been suggested. As the Entry class is vendor-provided, I did all its ORM work in an orm.xml file. When persisting, I persist EntryWrapper.
I don't have much experience with JPA, but I wouldn't extend your base classes, instead I would wrap them:
public class PersistMe<T> {
#Id
private long id;
private T objToWrap;
public(T objToWrap) {
this.objToWrap = objToWrap;
}
}
I can't test it, if it doesn't work let me know so I can delete the answer.

JPA entity with a interface attribute, is it possible?

I have the following entity:
#Entity
public class TestCaseStep implements JPAEntity<Integer> {
...
#Column(name="STEP_NUMBER")
private Integer stepNumber;
#Enumerated(EnumType.STRING)
#Column(name="ACTION")
private Action action;
**#ManyToOne
#JoinColumn(name="connector")
private ScriptItem connector;**
My attribute ScriptItem is a interface for 3 other classes. Is it possible to configure JPA to set the correct class id in runtime execution?
Other resources:
public interface ScriptItem {
String getValue();
ScriptItemType getType();
}
#Entity
#Table(name="DAT_FEED_XML")
public class FeedXml implements JPAEntity<Integer>, ScriptItem {
...
}
#Entity
#Table(name="DAT_DB_STMT")
public class DbStatement implements JPAEntity<Integer>, ScriptItem {
...
}
Which annotations should I use to let JPA understand that I want to save the id of one of the 3 classes?
Thanks in advance,
It is really a good idea but unfortunately directly mapping interfaces as an entity attribute is not supported by JPA.
You can only map top level classes directly annotated with #Entity. This top level class may implement an interface though.
This feature has been requested and discussed for a long time.
Also take a look at this and this.
Depending on what you're trying to accomplish, #Inheritance annotation with table-per-class strategy could be an option.
I hope it helps.
It is possible with one caveat - you have to point JPA to a target entity which should be a concrete class. However, it can be an abstract class which implements your interface. So one principle of good design you'll have to break and in particular - "favour composition over inheritance".
Here's how to do it:
In your user class (which references your interface Task):
#OneToOne(targetEntity = BaseTask.class)
private Task task;
so here Task is an interface, but you have to declare an abstract class BaseTask.
In your BaseTask:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="task_type")
#Table(name="Task")
public abstract class BaseTask implements Task{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
}
Here the important thing is #DiscriminatorColumn - since all fields of the inheritance tree will be stored in 1 table (you specified that with the #Inheritance(strategy = InheritanceType.SINGLE_TABLE) annotation above. So this discriminator column will contain a label which will allow JPA to differentiate what kind of task you're talking about
Your concrete classes:
#Entity
#DiscriminatorValue("api")
public class ApiTask extends BaseTask {
or
#Entity
#DiscriminatorValue("ssh")
public class SshTask extends BaseTask{
As you can see the discriminator value tells JPA what task it is going to load (what class to instantiate).
No, not possible with JPA or Hibernate.
It does seem strange, when coding in the Java language which allows for attributes to be interfaces, that a persistence standard like JPA, intended for Java, does not support persisting attributes that are interfaces.
I always found it really very frustrating when my ORM would force me to refactor my 'pure' OO model just so that it could persist it.
It's not that it's technically impossible to implement persisting of interface attributes - in fact JDO has supported persistence of interfaces since forever which is why I started using it years ago for all of my own projects.
I've been tempted to switch to JPA, not because it is technically superior (in fact, quite the opposite) but just because of "herd mentality".
In recent contract work I have been forced to gain experience with JPA/Hibernate and in doing so, have lived out the many limitations and inefficiencies of that combination compared with JDO/DataNucleus. This was a great experience because it helped me quell my desire to join "the herd" :)
You need to setup your inheritance of ScriptItem correctly in JPA using whatever strategy you prefer (see the docs) and then JPA will be smart about it.

Extend entity classes with composite keys in hibernate

In our company we have a strange database model which can't be modified because to many systems works with them. Up to know we have a straight java application which connects with hibernate to the database and loads the data. We have for each table one xml mapping file.
The strange thing about the database is that we do not have any primary keys. Most table have a unique index containing several columns.
Now we want to use an application server (jboss) and the ejb model. So I created a class like this:
#Entity
#Table (name = "eakopf_t")
public class Eakopf implements Serializable {
#Embeddable
public static class EakopfId implements Serializable {
private String mandant;
private String fk_eakopf_posnr;
// I removed here the getters and setters to shorten it up
}
#Id
private EakopfId id;
private String login;
// I removed the getters and setters here as well
}
This works perfect.
Because our customers have different versions of the database schema I thought about extending this class on each database release change. So each interface we create with java can decide which version of the table will be used.
Here is the extended table class
#Entity
#Table (name = "eakopf_t")
public class Eakopf6001 extends Eakopf implements Serializable {
private String newField;
// getters and setters
}
If I use Eakopf (the base version) it is working if I do something like that:
EakopfId id = new EakopfId();
id.setMandant("001");
id.setFk_eakopf_posnr("ABC");
Eakopf kopf = (Eakopf) em.find(Eakopf.class, id);
But if I do this:
EakopfId id = new EakopfId();
id.setMandant("001");
id.setFk_eakopf_posnr("ABC");
Eakopf6001 kopf = (Eakopf6001) em.find(Eakopf6001.class, id);
this exception occues
javax.ejb.EJBException: javax.persistence.PersistenceException:
org.hibernate.WrongClassException: Object with id:
de.entity.Eakopf$EakopfId#291bfe83 was not of the specified subclass:
de.entity.Eakopf (Discriminator: null)
Does anybody has an idea?
many greetings,
Hauke
Doing what you did means to Hibernate that you're storing two different kinds of entities in a single table. This is possible is you use a discriminator column. But if I understand correctly, you just want one kind of entity in the table : Eakopf6001. In this case, its base class should be annotated with #MappedSuperClass, not with #Entity.
I would suggest creating a class annotated with #MappedEntity (let's call it BaseEakopf), and two entities: EaKopf and EaKopf6001, each with their set of additional fields. Include one of the other of the entities in the list of mapped classes, depending on which one you want to use.
My personal opinion is that if you have multiple versions of your app, they should use the same entities, but with different fields. Your version control system would take care of these multiple versions, rather than your source code (i.e. have one set of source files per version of the app, rather than one single set of source files for all the possible versions).

Categories

Resources