Javax's #Transient annotation when applied over an #Entity class' field will prevent the annotated field from being persisted into the database as a column. Is there a method to selectively achieve this behavior (of excluding the persistence of a certain column) for a field in a MappedSuperclass?
To clarify, I want some field x present in a MappedSuperclass to be persisted for some entity classes that extend the MappedSuperclass and excluded from persistence in some other extending entity classes.
I have tried shadowing the field x in the extending class and annotating it with #Transient, however, this doesn't seem to work. Is there any alternative approach that would enable this behavior?
Yes. In the children entity class that extends #MappedSuperclass , you can configure it to use the property access for this transient field .
So assuming a given #MappedSuperclass has a #Transient field :
#MappedSuperclass
public abstract class Parent {
#Transient
protected LocalDateTime createdTs;
}
For the children entity that want to include this transient field , you could do :
#Entity
#Table(name = "foo")
public class Foo extends Parent {
#Id
private Long id;
#Access(AccessType.PROPERTY)
#Column(name= "createTs")
public LocalDateTime getCreatedTs() {
return this.createdTs;
}
}
And for the children entity that want to exclude this transient field , you could do :
#Entity
#Table(name = "foo")
public class Foo extends Parent {
#Id
private Long id;
}
Related
I'm dealing with a couple of Entities with Tree like structures that were getting more complicated so I decided to create an abstract class for it so code was a bit more mainainable:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class TreeStructure<T extends TreeStructure>
{
#ManyToOne
protected T parent;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
protected Set<T> children = new HashSet<>();
//...
Then I have two Entities which extend it:
#Entity(name = "TreeStructureOne")
public class TreeStructureOne extends TreeStructure<TreeStructureOne>
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty("TreeStructureOne_id")
private long id;
And I basically want the database to be completely unaware of this TreeStructure abstraction and save all of the fields in each Entities tableand expected InheritanceType.TABLE_PER_CLASS to deal with that. But it seems I need to define the Id in the TreeStructure Entity at least or I get:
Invocation of init method failed; nested exception is org.hibernate.AnnotationException: No identifier specified for entity: TreeStructure
And I don't want to add an ID into the abstract class since this makes three tables in the database called: HT_TREE_STRUCTURE, HT_TREE_STRUCTURE_ONE and HT_TREE_STRUCTURE_TWO with one field ID each one.
Is there any solution to that?
Since TreeStructure is not an #Entity use only #MappedSuperclass
#MappedSuperclass
public abstract class TreeStructure<T extends TreeStructure> {
instead of #Entity and #Inheritance for the parent class.
You can find #MappedSuperclass in the Oracle JEE API documentation.
I have SuperClass where I have defined my properties and I want to apply one more annotation on one of the SuperClass Property.
#MappedSuperclass
public class CartBaseEntity {
private String cartName;
#Column(name = "cart_name")
public String getCartName() {
return cartName;
}
public void setCartName(String cartName) {
this.cartName = cartName;
}
}
And my Sub Class is in below:
#Entity
#Table(name = "CART2")
public class CartEntity extends CartBaseEntity implements Serializable {
private Set<Items> items;
#Basic(fetch = FetchType.LAZY)
#Override
public String getCartName() {
return super.getCartName();
}
}
I was trying to override the 'cartName' column and want to add #Basic annotation on it. Is it possible or is there any workarround? TIA
Yes, it's possible with #AttributeOverride annotation applied to a subclass:
#Entity
#Table(name = "CART2")
#AttributeOverride(name = "cartName", column = #Column(name="CART_NAME"))
public class CartEntity extends CartBaseEntity implements Serializable {
...
}
UPDATE: here's what JPA 2.1 Specification tells about overriding a column in a mapped superclass:
11.1.4 AttributeOverride Annotation
The AttributeOverride annotation is used to override the mapping of
a Basic (whether explicit or default) property or field or Id
property or field.
The AttributeOverride annotation may be applied to an entity that
extends a mapped superclass or to an embedded field or property to
override a Basic mapping or Id mapping defined by the mapped
superclass or embeddable class (or embeddable class of one of its
attributes).
I have parent child relationship build this way (came from legacy system)
#Entity
#Table
class A implements Serializable {
........
#jsonmanagedreference("test")
#OneToMany(mappedBy="PK.id", fetch = FetchType.LAZY,)
Set<B> b = new HashSet<B>()
......
setters / getters
}
#Embeddable
class PK {
#jsonbackreference("tets") // can't find it
#ManyToOne
#JoinColumns
A a
}
#Entity
#Table
class B implements Serializable {
#EmbeddedId
private PK pk;
setters / getters
}
It works fine with regular operations, the problem is I can not serialize A object because circular reference.
After I tried to add #jsonmanagedreference to A.b and #jsonbackreference to PK.a it did not work because it could not find JsonBackReference, is there a way to manage parent child relationship during serialization if child in Embedded class or nested?
I used this solution:
Read embedded object in Jackson
It worked for me, just using #JsonUnwrapped on embedded class reference and mapping the embedded id with: #JsonIdentityInfo
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "yourEmbeddedIdAtribute")
i have a generic class which is supper class of some non-generic class and those are just setting its generic parameter like this:
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
class A<T>{
#Id
getId(){..}
setID(int id){..}
int id
T t;
T getT(){...}
setT(T t){...}
}
and
#Entity
class B extends A<Integer>{}
but hibernate says that B does not have an identifier what should I do?
If A won't be directly persisted, but you do want it's subclasses to pick up some (or all) of its Hibernate annotations, you should use #MappedSuperclass:
#MappedSuperclass
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
class A<T>{
#Id
getId(){..}
setID(int id){..}
int id
T t;
T getT(){...}
setT(T t){...}
}
You need to add the #Entity annotation to class A as well.
The #Transient annotation on attribute t should help with your second exception
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
class A<T> {
#Id
getId(){..}
setID(int id){..}
int id
#Transient
T t;
T getT(){...}
setT(T t){...}
}
I agree with reply No. 1, use #MappedSuperclass for A - don't make something abstract an Entity.
You should probably make this class specifically abstract too.
#MappedSuperclass
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
abstract class A<T>{
#Id
getId(){..}
setID(int id){..}
int id
T t;
T getT(){...}
setT(T t){...}
}
A table-per-class strategy often requires this kind of abstract base.
Then the subclass specifies the table name, and additional fields.
#Entity
#Table(name="MY_INTEGERS")
class B extends A<Integer>{}
(Personally I would move this variable type into the subclass, but I don't know what you're trying to achieve).
After lots of testing, trying to get Java parameterisation working with an abstract parent (Single-table inheritance), and an abstract child table (one-table-per-class inheritance), I've given up.
It may be possible, but often you get problems where Hibernate tries to instantiate an abstract (parameterised) class as an entity. this is when you get the error "A has an unbound type and no explicit target entity."
It means Hibernate doesn't have a parameter value for a parameterised type.
I found that tests for the extending classes were fine, but tests around parent entities would break.
I would suggest rewriting it using the JPA inheritance, moving the parameterised stuff down into extending classes. That way you get the same polymorphism back from the database.
#MappedSuperclass
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "CLASS_TYPE", discriminatorType = DiscriminatorType.STRING)
public abstract class ClassA {
[...]
}
extension B:
#Entity
#DiscriminatorValue=("B")
public class ClassB extends ClassA {
#OneToOne
#JoinColumn(name = "mycolumn_id")
private Integer instance;
[...]
}
extension C:
#Entity
#DiscriminatorValue=("C")
public class ClassC extends ClassA {
#OneToOne
#JoinColumn(name = "mycolumn_id")
private String instance;
[...]
}
I have two hibernate classes: a base class, and an extended class that has additional fields. (These fields are mapped by other tables.)
For example, I have:
#Entity
#Table(name="Book")
public class A {
private String ID;
private String Name;
// ...
}
#Entity
#Table(name="Book")
public class B extends A {
public String node_ID;
// ...
}
public class Node {
public String ID; // maps to B.node_ID
// ...
}
How do I map this in Hibernate? The hibernate documentation states three types of inheritence configurations: one table per class, one table with a type column, and a join table -- none of which apply here.
The reason I need to do this is because class A is from generic framework that's reused over multiple projects, and class B (and Node) are extensions specific to one project -- they won't be used again. In the future, I may have perhaps a class C with a house_ID or some other field.
Edit: If I try the above pseudo-code configuration (two entities mapped to the same table) I get an error that the DTYPE column doesn't exist. The HQL has a "where DTYPE="A" appended.
This is possible by mapping the #DiscriminatorColumn and #DiscriminatorValue to the same values for both classes; this can be from any column you use that has the same data regardless of which type (not sure if it works with null values).
The classes should look like so:
#Entity
#Table(name="Book")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="published")
#DiscriminatorValue(value="true")
public class A {
private String ID;
private String Name;
// ...
}
#Entity
#Table(name="Book")
#DiscriminatorValue(value="true")
public class B extends A {
public String node_ID;
// ...
}
For anyone who got here like me and does not want to have the dtype column but instead want to use the same table for more than one entity as is I would recommend using this
Basically you can create a Base like this
#MappedSuperclass
public abstract class BaseBook<T extends BaseBook> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
... any other variables, getters + setters
}
#Entity
#Table(name= "book")
public class BookA extends BaseBook<BookA>{
//Default class no need to specify any variables or getters/setters
}
#Entity
#Table(name= "book")
public class BookB extends BaseBook<BookB>{
#Column(name = "other_field")
private String otherFieldInTableButNotMapedInBase
... Any other fields, getter/setter
}
From the above we have created base super class which does not have any entity or table mapping. We then create BookA to be default with the Entity + Table mapping. From there we can create other Entities all extending from BaseBook but pointing to one table