Ok, this question is best explained in code. So will try to present the most succinct example I can.
Timestamped.java
#Embeddable
public class Timestamped<E> {
private E value;
private Date timestamp;
...
}
Foo.java
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE")
public class Foo {
#Embedded
#AttributeOverides({
#AttributeOverride(name="timestamp", column=#Column("VALUE_TS")),
#AttributeOverride(name="value", column=#Column("VALUE"))
})
private TimestampedValue<E> value;
...
}
Bar.java
#Entity
#DiscriminatorValue("BAR")
public class Bar extends Foo<Double> { }
What I need is for Bar to use the appropriate type converter for value.value and a different converter for each subclass of Foo. Ideally I would just like to augment this code, but I would be OK making Foo abstract and moving the value field to each of the subclasses with additional annotations.
The first approach is not going to work - you can't persist "genericized" classes.
You will either have to move value into concrete subclasses like you've suggested OR write a UserType to persist your Timestamped component.
If what you're trying to do is make many classes that correspond to many tables but use the same column names for the 'timestamp' and 'value' properties, then what you want is a 'mapped superclass' with those columns, not an embedded class. Research the #MappedSuperclass annotation.
You are running into an erasure problem. Hibernate cannot know what to do with the generic types, because that information is not available at runtime. It would be nice though.
Related
In my application I have multiple objects that I would like to add comments to. Every one of these objects is represented in its own database table. Beside being connected to a specific object, all comments share a common context in which the corresponding objects exist. What I tried for now is to use JPA-inheritance with InheritanceType.SingleTable so I can store the foreign keys to every 'commentable'-object in one table and the discriminator-feature to seperate that table into different Comment-Subclasses in JPA:
Superclass Comment.java
#Entity
#Table(name = "COMMENT_TABLE")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "COMMENT_OBJECT_TYPE")
public class Comment {
protected String text;
protected CommonContext context;
...
}
Subclass Object A
#Entity
#DiscriminatorValue(value = "OBJECT A")
public class ObjectAComment extends Comment {
private ObjectA objectA;
// OneToMany-Relation exists in Object A accordingly
#JoinColumn(name = "FK_OBJECT_A")
#ManyToOne
public ObjectA getObjectA() { return objectA; }
public void setObjectA(ObjectA objectA) { this.objectA = objectA; }
}
The other comment-classes for the other objects are designed just as for object A. The common context shall be used to get all comments for a specific situation and I would like to have a comment know its owner, so that I can easily link to that object in my application. Without the latter I had to go through all objects of that type to search for any that has comments, as not every object has them.
On designing the REST-endpoints and the EJBs I ended up creating specific methods for every subclass of Comment.java. For example for creating a comment I have
#POST
#Path("comments/objectA")
public Response createCommentForObjectA(ObjectAComment comment) { ... }
#POST
#Path("comments/objectB")
public Response createCommentForObjectB(ObjectBComment comment) { ... }
...
This feels a bit cumbersome as I would rather have
#POST
#Path("comments")
public Response createComment(Comment comment) { ... }
which is impossible with the current design as I would lose the specific information for the different objects. Now I see three possible ways to go on:
Version 1
I stick with the current solution and create CRUD-methods for every type of comment.
Version 2
A friend suggested, that I could use transient properties in Comment.java:
public class Comment {
...
private COMMENT_OBJECT_TYPE objectType;
private long idObject;
#Transient
public long getIdObject() { return idObject; }
...
#Transient
public COMMENT_OBJECT_TYPE getObjectType() { return objectType; }
...
}
With this I could generalize the parameter of the REST-endpoint and return specific objects depending on the object type:
#POST
#Path("comments")
public Response createComment(Comment comment) {
// return ObjectAComment, ObjectBComment, ... depending on the object type
}
Version 3
Ditch the whole #Inheritance and #DiscriminatorColumn, put everything in one JPA-class and do the whole organizing of the comment context myself. Additionaly I would lose type safety.
None of these solutions feels completely right to me, hence I would like to ask if there is a preferable way to design this kind of comment feature and is there maybe something I am missing completely?
Edit 1
Added information that all comments and objects share a common context. Renamed previous COMMENT_CONTEXT to COMMENT_OBJECT_TYPE to avoid a misunderstanding between this common context and the object type a comment is related to.
It seems to me like your Comment is a standalone entity without dependencies on other entities. A comment has an owner, but should not know who is owning it. So I would add a column on the comment table "ownerUuid". The entire comments "bounded context" knows nothing about the other entities.
When creating a comment you always provide the ownerUuid. Same for retrieval. So you can create comments for any entity having a uuid.
However this means you need to add UUID columns in your already existing tables.
This to me seems like the cleanest solution. This way your comment system can stand on it's own without heavy impact on other entities.
EDIT
Because of the extra information. I would suggest following approach.
Keep in mind that I do not know how the owner of the Comment is used, so the suggestion might not be perfect for this scenario.
As the comment should know the owner object I would suggest doing the following:
Have an interface CommentOwner with methods:
getUuid()
getContext()
Any other information you might need from the owner
A Comment will have a CommentOwner property.
Every entity that you want to contain Comments, should implement this interface. When creating a Comment you provide the CommentOwner.
This way you can retrieve comments Based on Context. A Comments has a direct link to its owner, but still does not need to know about the specific classes of the owners.
In the end I went with version 3, keeping every information in one Comment-class. The subclasses which I would've achieved with #Inheritance and #DiscriminatorColumn would only have one property, the foreign key to the commentable object, and wouldn't differ in what they represent in general and how they would be used.
My class looks something like this now:
public class Comment {
private String text;
private CommonContext context;
private COMMENT_OBJECT_TYPE objectType;
private ObjectA objectA;
private ObjectB objectB;
...
#JoinColumn(name = FK_OBJECT_A)
#ManyToOne
public ObjectA getObjectA() { return objectA; }
public void setObjectA(ObjectA objectA) { this.objectA = objectA; }
...
}
Is it possible to have a column definition inside a super class Entity for use by sub class Entities?
I have adopted the table-per-subclass hierarchy to represent different types of 'businesses' which inherit from a 'super business'. So each business type has its own table in the database and there is also a generic 'business' table which contains information which is common to all business types.
Each of these businesses has a foreign key column called 'parent_id' which points to another business of the same type (so businesses can belong to other businesses of the same type). This means each of my business type classes has its own 'parent' attribute with corresponding getters and setters.
I want to use generics to declare a 'parent' attribute (along with getters and setters) in the 'super business' so that it can be written once for all businesses instead of once for every type of business.
I achieved something close to this by putting this stuff into a new #MappedSuperClass (CommonBusiness) between my 'super business' class and my 'business type' classes, which looks like this:
SuperBusiness > CommonBusiness > (BusinessType1, BusinessType2, BusinessType3)
But I want to know if it's possible do this without the 'CommonBusiness' class in between.
My original question could be rephrased as: Is it possible to define columns in a superclass Entity so that the child Entity treats some columns as if they are from a MappedSuperClass?"
(I've looked everywhere and haven't found anything! Also I can't post code, because it doesn't belong to me, sorry!)
I would do something like this:
public class SuperBusiness<T extends SuperBusiness> {
protected T parent;
...
}
public class CommonBusiness<T extends SuperBusiness> extends SuperBusiness<T> {
...
}
public class BusinessType1 extends CommonBusiness<BusinessType1> {
...
}
public class BusinessType2 extends CommonBusiness<BusinessType2> {
...
}
public class BusinessType3 extends CommonBusiness<BusinessType3> {
...
}
I have a simple entity class like this
#Entity
public class Car{
#Column protected String name;
}
Everything is ok but now I want to use subclasses or anonymous classes of this entity.
public class TestCar extends Car{
TestCar(){ this.name = "Test"; }
}
or
void foo(){
Car c = new Car(){
{ this.name = "Lone"; }
};
// ...
}
These subclasses are just for instantiation purposes and can be ignored completely by hibernate.
But when I try to save the entity I get an "Unknown entity"-Exception.
Is there a way that hibernate ignores such subclasses?
Edit: It would be nice if we could find an answer to the question. It is not helpful (at least not for me) to discuss all the other (well known) pattern. You should see that this is only a strongly simplified example to clarify the problem. (Probably you should just ignore the use-cases)
Just found this possible duplicate (also no solution): How to persist an entity from an non-entity subclass in Hibernate
It is not going to work.
IMHO you should rethink your design. Is realy TestCar or anonymous Car class a subtype of Car? I think you are using wrong tool for creating instances. You can use Builder pattern.
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 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.