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.
Related
Imagine the following scenario where we use inheritance strategy TABLE_PER_CLASS and Template as superclass while Product as subclass.
Template:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#Table(name = "Templates")
#NamedQuery(name = "getAllTemplates", query = "SELECT t FROM Template t")
public class Template implements Serializable { ...}
Product:
#Entity
#Table(name = "Product")
public class Product extends Template implements Serializable { ... }
In this scenario even thought i have in my DB 2 templates and 1 product. Whenever i call the Template namedQuery i retrieve both Products and Templates alike.
I tried do something like so:
SELECT t FROM Template t WHERE TYPE(t) = Template
However it returns the following error:
The class does not have a descriptor, or a descriptor that does not use inheritance or uses a ClassExtractor for inheritance
Is there a way to only get the Templates?
The TYPE operator does not work for sub classes either when using TABLE_PER_CLASS. There seems not to be explicit information about using TYPE with TABLE_PER_CLASS.
However there are lots of posts saying that this strategy is inefficient and not exactly recommended to be used.
JPA 2.1 specifications say about TABLE_PER_CLASS:
Support for the TABLE_PER_CLASS mapping strategy is optional in this release.
This means also that support might be only partial: like TYPE support not implemented.
Also there are some posts that indicate that not only Hibernate suffers from this, see (some pretty old, but still), like: this and this.
So as a conclusion:
change to SINGLE_TABLE or JOINED strategy if possible
live with it
In Hibernate you could also try to get it working with #DiscriminatorColumn and adding the column to Template entity but I personally think it is not worth the effort.
I have a hierarchy in my domain model, which is described by classes:
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class BaseEntity {
#Id
private Long id;
// other fields
}
#DiscriminatorValue(value = "Individual")
public class IndividualEntity extends BaseEntity {
// fields
}
#DiscriminatorValue(value = "Branch")
public class BranchEntity extends BaseEntity {
// fields
}
I'm fetching objects like this:
Specification<BaseEntity> specification = createSpecification();
BaseEntity entity = baseRepository.findOne(specification);
(I'm using spring-data)
The problem is that Hibernate returns proxy object (what I understand), but the proxy is of BaseEntity, not the proper subclass (its' class is BaseEntity_$$_jvsted9_26, therefore entity instanceof IndividualEntity is false).
What is interesting, not all objects are returned as proxy.
I'm fetching entities in loop (common transaction), some of them are returned in normal form (i.e. IndividualEntity/BranchEntity), some as proxies.
If I change mechanism, so that every fetch is done in separate transaction - no proxy objects are returned at all.
I know that I can unwrap that proxy (e.g. like here), but what is the reason for such behaviour (kinda strange for me) and can I avoid it?
Can't be certain without seeing more of the object model, but one reason Hibernate would do this is if the BaseEntity had already had to be resolved as a proxy for the same BaseEntity.id earlier in the session.
For example, if there is another class that has a ToOne relation to a BaseEntity, it will just have a foreign key to the id, so will use a BaseEntity_$$... proxy to delay resolving the correct subclass for the other end. This then becomes the instance for that id that is managed in the Hibernate PersistenceContext.
Clearly a Hibernate.unwrap(), or one of the other options in the link above will reveal the 'true' instance. One other option is to use abstract methods on BaseEntity (e.g. isIndividual()). This can look a bit tidier, but ultimately Hibernate will still need to resolve the proxy when the method is called.
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.
I'm not sure this is possible, but knowing just the very basics of JPA, I want to ask if it is possible. Basically I have an entity (We'll call it MyEntity) with a bunch of fields on it. We now want a 2nd entity that has all the same fields as MyEntity plus some of it's own. The use case for this is archiving these entities. We want to store all the archived entities in a separate table than MyEntity so that we don't have to qualify all the queries with archived=false. The JPA annotations for MyEntity look something like this:
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE")
public abstract class MyEntity
{
....
There are multiple classes that extend this abstact class, each with #DiscriminatorValue annotations
For my archived entity (MyArchivedEntity) I want something along the lines of this:
#Entity
public class MyArchivedEntity
{
private MyEntity entity;
private String archiveSpecificField;
....
The problem with this of course is that it will want to join into the MyEntity table and get a specifc MyEntity record for populate the entity field. Is there some kind of annotation or something I can do to just get the same fields/columns from that entity (MyEntity) into this entity (MyArchivedEntity)?
Like I said in the beginning, I'm not sure if this is possible, but I hope I've explained well enough the end goal of what I'm trying to achieve, so that there could be some way to achieve it. If it makes any difference, I'm using PostgreSQL with EclipseLink.
What you can do is using #MappedSuperclass on a AbstractParentEntity becoming the super class of both MyEntity and MyArchiveEntity. So you will have something like the following:
#MappedSuperclass
public abstract class AbstractParentEntity {
public String someField;
...
}
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE")
public abstract class MyEntity extends AbstractParentEntity
{
//here you don't have any field (they all move to AbstractParentEntity
// (or, at least all the fields that need to be archivied are now declared in parent class)
....
}
#Entity
public class MyArchivedEntity extends AbstractParentEntity
{
private String archiveSpecificField;
....
More about MappedSuperclass here:
Mapped superclass inheritance allows inheritance to be used in the object model, when it does not exist in the data model. It is similar to table per class inheritance, but does not allow querying, persisting, or relationships to the superclass. Its' main purpose is to allow mappings information to be inherited by its' subclasses. The subclasses are responsible for defining the table, id and other information, and can modify any of the inherited mappings. A common usage of a mapped superclass is to define a common PersistentObject for your application to define common behavoir and mappings such as the id and version. A mapped superclass normally should be an abstract class. A mapped superclass is not an Entity but is instead defined though the #MappedSuperclass annotation or the <mapped-superclass> element.
You may wish to look into EclipseLink's history support. It can automatically maintain a historical archive table.
See,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/History
Another option would be to map the same classes in another persistence unit using an orm.xml to the archive tables.
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.