I have an #Entity with three fields A, B, C out of which A and B act as composite primary key. I created an #EmbeddedId class holding A and B. To ease the burden of defining getters and setters i used lombok #Data annotation.
#Entity
#Data
public class MyClass {
#EmbeddedId
private PrimaryKey id;
}
#Embeddable
#Data
public class PrimareyKey implements Serializable {
private String A;
private String B;
}
I would not like to expose that A and B are the primary key and access A and access all fields in the same way.
//Exposes primary key
myObject.getid().getA();
myObject.getid().getB();
myObject.getC();
//Hides primary key
myObject.getA();
myObject.getB();
myObject.getC();
Currently one could use #IdClass tagging each filed as #Id as suggested in this answer but if I still need to use #EmbeddedId (or any #Embedded actually) the only way (I know) to achieve this is to write ad hoc getters and setters bypassing the id variable such as
#Entity
#Data
public class MyClass {
#EmbeddedId
private PrimaryKey id;
public String A getA(){
return id.getA()
}
public String A setA(String a){
id.setA(a);
}
//same for B and any other fiels in PrimaryKey
}
This looks like a lot of boilerplate code to write and maintain.
Is there an annotation to expose #EmbeddedId getters and setters?
In MyClass, add Lombok #Delegate annotation to your PrimaryKey. It should look like:
#Entity
#Data
public class MyClass {
#Delegate
#EmbeddedId
private PrimaryKey id;
}
Then you can set/get PrimaryKey fields directly from MyClass. Here is a link for you to read more about it.
You can use the AccessLevel with #Getter and #Setter as follows:
#Getter(AccessLevel.NONE)
#Setter(AccessLevel.NONE)
private PrimaryKey id;
When using #Data, you have the public access to accessors by default, and using AccessLevel.NONE will overwrite the default behaviour and will not allow to access the accessors.
Related
We're using Hibernate to generate JPA Metamodel - Classes for our Entities.
That's working quite fine for most cases, but if there's a relation (#ManyToOne) to an Entity in an #Embeddable, there's no SingularAttribute generated.
Classes are implemented like this (following a "Generation Gap Pattern"):
#Entity
public class EntityA extends EntityABase {
....
}
#MappedSuperClass
public abstract class EntityABase {
#EmbeddedId
private EntityAPrimaryKey primaryKey;
}
#Embeddable
public class EntityAPrimaryKey extends EntityAPrimaryKeyBase {
...
}
#MappedSuperClass
public class EntityAPrimaryKeyBase {
#ManyToOne
#NotNull
private EntityB entityB;
private String someText;
}
Result is like this
#Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
#StaticMetamodel(EntityAPrimaryKeyBase.class)
public abstract class EntityAPrimaryKeyBase_ {
public static volatile SingularAttribute<EntityAPrimaryKeyBase, String> someText;
}
So, the "ordinary" field someText is generated fine, but the Attribute for the relationship to EntityB is missing.
The expected output would be
#Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
#StaticMetamodel(EntityAPrimaryKeyBase.class)
public abstract class EntityAPrimaryKeyBase_ {
public static volatile SingularAttribute<EntityAPrimaryKeyBase, String> someText;
public static volatile SingularAttribute<EntityAPrimaryKeyBase, EntityB> entityB;
}
All other Metamodel-Classes are generated fine (EntityB, EntityA, EntityABase etc.)
I've tried removing the indirection between EntityAPrimaryKey and EntityAPrimaryKeyBase (and annotating the EntityAPrimaryKeyBase with #Embeddable), but that doesn't change the output.
Any ideas why the Attribute entityB isn't generated? Would be very helpful!
JPA Spec (11.1.17) - EmbeddedId Annotation
The EmbeddedId annotation is applied to a persistent field or property of an entity class or mapped superclass to denote a composite primary key that is an embeddable class. The embeddable class must be annotated as Embeddable.[104] Relationship mappings defined within an embedded id class are not supported.
JPA Spec (2.11.2) - Mapped Superclasses
A class designated as a mapped superclass can be mapped in the same way as an entity except that the mappings will apply only to its subclasses since no table exists for the mapped superclass itself.
You cannot have a relationship mapping within an #Embeddable that is to be used as an #EmbeddedId. Even tho you have the relationship in the #MappedSuperclass, 2.11.2 states that mappings are applied to the subclasses, which in this case is the #Embeddable.
For the record, changing the class structure too (and thus making it according to the spec) solves the Problem:
#Entity
public class EntityA extends EntityABase {
....
}
#MappedSuperClass
public abstract class EntityABase {
#EmbeddedId
private EntityAPrimaryKey primaryKey;
#ManyToOne
#MapsId("entityBID")
private EntityB entityB;
}
#Embeddable
public class EntityAPrimaryKey extends EntityAPrimaryKeyBase {
...
}
#MappedSuperClass
public class EntityAPrimaryKeyBase {
private Long entityBID;
private String someText;
}
I am creating entities that are the same for two different tables. In order do table mappings etc. different for the two entities but only have the rest of the code in one place - an abstract superclass. The best thing would be to be able to annotate generic stuff such as column names (since the will be identical) in the super class but that does not work because JPA annotations are not inherited by child classes. Here is an example:
public abstract class MyAbstractEntity {
#Column(name="PROPERTY") //This will not be inherited and is therefore useless here
protected String property;
public String getProperty() {
return this.property;
}
//setters, hashCode, equals etc. methods
}
Which I would like to inherit and only specify the child-specific stuff, like annotations:
#Entity
#Table(name="MY_ENTITY_TABLE")
public class MyEntity extends MyAbstractEntity {
//This will not work since this field does not override the super class field, thus the setters and getters break.
#Column(name="PROPERTY")
protected String property;
}
Any ideas or will I have to create fields, getters and setters in the child classes?
Thanks,
Kris
You might want to annotate MyAbstractEntity with #MappedSuperclass class so that hibernate will import the configuration of MyAbstractEntity in the child and you won't have to override the field, just use the parent's. That annotation is the signal to hibernate that it has to examine the parent class too. Otherwise it assumes it can ignore it.
Here is an example with some explanations that may help.
#MappedSuperclass:
Is a convenience class
Is used to store shared state & behavior available to child classes
Is not persistable
Only child classes are persistable
#Inheritance specifies one of three mapping strategies:
Single-Table
Joined
Table per Class
#DiscriminatorColumn is used to define which column will be used to distinguish between child objects.
#DiscriminatorValue is used to specify a value that is used to distinguish a child object.
The following code results in the following:
You can see that the id field is in both tables, but is only specified in the AbstractEntityId #MappedSuperclass.
Also, the #DisciminatorColumn is shown as PARTY_TYPE in the Party table.
The #DiscriminatorValue is shown as Person as a record in the PARTY_TYPE column of the Party table.
Very importantly, the AbstractEntityId class does not get persisted at all.
I have not specified #Column annotations and instead are just relying on the default values.
If you added an Organisation entity that extended Party and if that was persisted next, then the Party table would have:
id = 2
PARTY_TYPE = "Organisation"
The Organisation table first entry would have:
id = 2
other attribute value associated specifically with organisations
#MappedSuperclass
#SequenceGenerator(name = "sequenceGenerator",
initialValue = 1, allocationSize = 1)
public class AbstractEntityId implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(generator = "sequenceGenerator")
protected Long id;
public AbstractEntityId() {}
public Long getId() {
return id;
}
}
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "PARTY_TYPE",
discriminatorType = DiscriminatorType.STRING)
public class Party extends AbstractEntityId {
public Party() {}
}
#Entity
#DiscriminatorValue("Person")
public class Person extends Party {
private String givenName;
private String familyName;
private String preferredName;
#Temporal(TemporalType.DATE)
private Date dateOfBirth;
private String gender;
public Person() {}
// getter & setters etc.
}
Hope this helps :)
Mark the superclass as
#MappedSuperclass
and remove the property from the child class.
Annotating your base class with #MappedSuperclass should do exactly what you want.
This is old, but I recently dealt with this and would like to share my solution. You can add annotations to an overridden getter.
#MappedSuperclass
public abstract class AbstractEntity<ID extends Serializable> implements Serializable {
#Column(name = "id", nullable = false, updatable = false)
#Id
private ID id;
public ID getId() {
return id;
}
...
}
#Entity
#Table(name = "address")
public final class Address extends AbstractEntity<UUID> implements Serializable {
...
#Override
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
public final UUID getId() {
return super.getId();
}
...
}
I am new to JPA and am having some difficulty understanding the "Direction in Entity Relationships" concepts as described here:
http://docs.oracle.com/javaee/7/tutorial/doc/persistence-intro001.htm#BNBQI
Is uni- or bidirectionality something that you choose when designing your entities or is it given by the database schema? Like in the order application (http://docs.oracle.com/javaee/7/tutorial/doc/persistence-basicexamples001.htm), could you for example design it so that the lineitem knows about which orders it belongs to, but an order wouldn't know which lineitems it has?
You decide whether a relationship is uni-directional or bi-directional by the fields and annotations you include on the entities.
Uni-directional
#Entity
public class Parent(){
#OneToMany
private List<Child> children;
}
#Entity
public class Child(){
}
Bi-directional
#Entity
public class Parent(){
#OneToMany
private List<Child> children;
}
#Entity
public class Child(){
#ManyToOne
#JoinColumn
private Parent parent;
}
As you can see the uni-directional relationship does not allow the child to access the parent, while the bi-directional does allow parent access. This link is created by adding an annotated field to the child of the parent's type and is completely optional. It boils down to a design decision.
Of course the database must support the relationship, meaning the proper primary/foreign keys are established to link the tables, but nothing special is required in your database.
One important concept to be aware of when modeling these relationships is the owning entity. I have written this article about the topic which may be helpful.
That depend upon your requirement
Unidirectional
#Entity
#AutoProperty
public class OneToOneUnidirectionalA implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#OneToOne
private OneToOneUnidirectionalB b;
private String s;
// Setters, Getters, Constructors, Pojomatic...
}
#Entity
#AutoProperty
public class OneToOneUnidirectionalB implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
// No reference to OneToOneUnidirectionalA
// since this is a unidirectional relationship
private String s;
// Setters, Getters, Constructors, Pojomatic...
}
Bidirectional
A owns the relationship. We need to avoid Pojomatic circular reference issues too:
#Entity
#AutoProperty
public class OneToOneBidirectionalA implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Property(policy=PojomaticPolicy.NONE)
#OneToOne
private OneToOneBidirectionalB b;
// Setters, Getters, Constructors, Pojomatic...
}
#Entity
#AutoProperty
public class OneToOneBidirectionalB implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Property(policy=PojomaticPolicy.NONE)
#OneToOne(mappedBy="b")
private OneToOneBidirectionalA a;
// Setters, Getters, Constructors, Pojomatic...
}
I'm trying to use hibernate to map an object like this:
#Entity
public class ParentClass {
#Id
#GeneratedValue
int Id;
#OneToMany
Map<String, ChildClass> map;
}
#Entity
public class ChildClass {
#Id
#GeneratedValue
int Id;
String text;
}
I don't want Hibernate to create a join table. I want it to add a column to the table for ChildClass. I'd also prefer not to add a field for the key in ChildClass. Ideally, when saving the object Hibernate would automatically take the key in the map and save it in the corresponding table, and do the reverse when querying. Is this possible?
If I do have to add a field to ChildClass for the key, can hibernate populate this field automatically with the key from the map? The reason I ask is because I'm getting my data from a JSON web service and using Jackson to parse it and I don't know of a way to make Jackson copy the keys to the fields in the value objects. I could write code to do that manually, but I`d rather avoid that.
Unidirectional relation without jointable:
#Entity
public class Customer implements Serializable {
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinColumn(name="CUST_ID")
public Set<Ticket> getTickets() {
...
}
#Entity
public class Ticket implements Serializable {
... //no bidir
}
Bidirectional without jointable:
#Entity
public class Troop {
#OneToMany(mappedBy="troop")
public Set<Soldier> getSoldiers() {
...
}
#Entity
public class Soldier {
#ManyToOne
#JoinColumn(name="troop_fk")
public Troop getTroop() {
...
}
It's from documentation: http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/
Apply these samples to your case.
I have an unowned relationship in my Domain model
#Entity
public class A {
#Id
private String id;
private Key firstB;
private Key secondB;
// getters & setters
}
#Entity
public class B {
#Id
private Key id;
private String name;
// getter & setter
}
KeyFactory.createKey(B.class.getSimpleName(), name) is the way I generate the Key for class B
I save B independently from A and assign it to an instance of A some time. The problem is that after saving A both fields firstB and firstA are null.
Any idea of what I'm doing wrong?
Key objects are not persisted by default so require explicit annotation which is why you are seeing null values.
Try annotating firstB and secondB as #Enumerated (this should really be #Basic but there is a bug which prevents this from working):
#Entity
public class A {
#Id
private String id;
#Enumerated
private Key firstB;
#Enumerated
private Key secondB;
}
Update: The latest SDK and DataNucleus JARs now correctly allow the use of #Basic.