I have a User, a Shop, and an Address entity.
Both a user and a shop can have an address.
What would be the best way to set up such a relationship using Spring JPA/Hibernate?
I had thought of creating an interface and let user and shop implement it, then use the interface in the address entity class to access the their common code. I couldn't get it to work, and I kinda feel like I'm over-complicating things. It might have looked something like this:
Addressable Address
|
+---+---+
| |
Shop User
#Entity
#Table(name = "shops")
public class Shop implements Addressable {
#OneToOne
#JoinColumn(name = "address_id")
private Address address;
#Column(name = "name", nullable = false)
private String name;
#Entity
#Table(name = "users")
public class User implements Addressable {
#OneToOne
#JoinColumn(name = "address_id")
private Address address;
#Column(name = "name", nullable = false)
private String name;
public interface Addressable {
String getName();
void setName(String name);
#Entity
#Table(name = "addresses")
public class Address {
#OneToOne
private Addressable addressable;
#Override
public String toString() {
return addressable.getName() + "\n" +
streetName + " " + streetNumber + "\n" +
postalCode + " " + cityName;
}
I might be waay off course, it doesn't quite feel right. I'm sure this is problem other people have encountered as well, though I as of yet to have found a nice if any solution.
Do you need your addresses to be separate entities? In other words, is there a specific need to store addresses in a dedicated table, or do you just want to group address related properties in a common object included in shop and user just for the purpose of code reuse? If the latter applies, you could make the address embeddable and mark it as embedded in your user and shop entities. They become additional properties in the user and shop table represented by the corresponding entities.
#Entity
#Table(name = "shops")
public class Shop {
#Embedded
private Address address;
#Entity
#Table(name = "users")
public class User {
#Embedded
private Address address;
#Embeddable
public class Address {
#Column(name = "name")
private String name;
public String getName() {...}
If you need to store them as separate entries in a dedicated table, using a "real" relationship is the correct approach (one-to-one, one-to-many annotations etc...)
Using an interface as a member of a relationship in JPA instead of a real object is not possible. A member of a relationship needs to be a POJO (a real object) because the JPA engine (like Hibernate) needs to be able to instantiate such classes in the background. Since you cannot instantiate an interface (or abstract class), you cannot use interfaces in relationships directly. One rather dirty trick could be working when defining custom converters that translate between the interface and a real POJO. This I have never tried before so I am not sure this will work. I also discourage this approach since it would imply some mechanism to choose the concrete class implementation to instantiate in your converter which seems very bad code design to me ;-)
What you also could try is create an abstract class storing the name property together with getter and setters and proper column annotations for all common properties. Mark this abstract class as MappedSuperclass and let your User and Shop class subclass this abstract class. Both subclasses have the superclass' common code inherited. The mappedsuperclass and your subclass code will be merged into one entity.
#Entity
#Table(name = "shops")
public class Shop extends Addressable{
...
#Entity
#Table(name = "users")
public class User extends Addressable{
...
#MappedSuperclass
public abstract class Addressable {
#Column(name = "name")
private String name;
public String getName() {...}
It looks like you are just using Java EE JPA, not Spring JPA or Hibernate.
There are data model patterns such as "the party model" where Person and Shop are subclasses of the same parent. (Parties have one or more Addresses and are People or Organizations, Shops are Organizations)
while you can use #MappedSuperClass to have a non-entity superclass, for your specific question I would look the Java EE JPA's #AttributeOverride. This helps to let JPA know that what in the Interface will be part of the Entity.
Related
I am trying to generate JPA classes for legacy RDMS project.
There is an entity class Person, written in JPA.
The entity Person has another Embeddale class called Address.
I can use set, list or map mapping for Embeddable Address. With any of these there can be multiple embedded objects in Person.
But the requirement is - there can be at most only one instance of embeddable object. How to achieve this requirement? I cannot use subclass entities, it has to be embeddable object only.
You can use single value association something like below
#Entity
public class Person {
#Id
private Long id;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "address_id")
private Address address;
}
#Embeddable
public class Address {
private String street;
private String city;
}
You can read more about #oneToOne here
Using #Embedded annotation the columns of #Embeddable class will be mapped to parent entity's table and hence will have only one instance.
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();
}
...
}
Writing the case it will be more simple to explain.
I am using Seam 2.3.1 v Hibernate JPA 2.0 and in our project. I have a base Person Entity Class.
#Entity
#Name("person")
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "person")
public class Person extends BaseEntity {
private String name;
private String surName;
private String email;
private String phone;
// getter & setters
}
And I have 3 more Entity extends from Person as #Inheritance(strategy = InheritanceType.JOINED): Personel, Musteri, DisPaydas
#Entity
#Name("personel")
public class Personel extends Person {
private String appellation;
// getter & setters
}
I want to List personels, musteris and dispaydas in my bean however when I set them in my Group Entity, I want to save them as Person.
In fact in DB there is no difference between person_id and personel_id, they are same. However when I listing it, they are List<Personel>
In summary:
I want to get List<Person> from List<Personel>
or Person from Personel object.
You're going to have to define an #Id and #Column in the Person class for the person_id.
However, since the column has a different name in the child entity, you'll need to change it using an #AttributeOverride to point to the personel_id #Column.
It couldn't hurt to use a #DiscriminatorColumn in the parent and #DiscriminatorValue in the children, but I don't think Hibernate requires those.
I use standard JpaRepository interfaces with the classes.
I have this classes:
User:
#Entity
#Table(name = "user")
#Inheritance(strategy = InheritanceType.JOINED)
public class User extends BaseEntity {
private Long id;
//Other Attr
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
//Getters & Setters...
}
Doctor:
#Entity
#Table(name = "doctor")
#PrimaryKeyJoinColumn(name = "id", referencedColumnName="id")
public class Doctor extends User {
private Long regNumber;
//Getters & Setters
}
I was searching and it seems that jpa/hibernate have no function/procedure for inserting a Doctor with info from an existing User.
I've tried to save a Doctor with info from a User query, it made a new User entry for the User table.
In theory, one can be an user without being a doctor, later one can become doctor.
In theory, one can be an user without being a doctor, later one can become doctor.
That's true in real life, but not with Java inheritance: an object of a given type can not become an object of another type. If you want to model that situation, inheritance is the bad tool.
You should use composition instead. A User can have a Doctor role. That's a OneToOne association, that can be mapped with the same tables as the ones you used to map your inheritance, and which allows a user to become a doctor.
It's also better design, because it allows for multiple roles: a user is a doctor AND a musician, for example. Something that would also not be possible with inheritance.
I want to achieve something like this:
#Entity
#Table(name = "beer")
public class Beer {
#Id Long id;
String brand;
String name;
}
#Entity
public class BeerWithIngredients extends Beer {
#OneToMany(mappedBy="beer")
List<BeerIngredient> ingredients;
}
#Entity
public class BeerIngredient {
#Id Long id;
// .. whatever fields
#ManyToOne
#JoinColumn(name = "beer_id")
BeerWithIngredient beer;
}
Physically, all beer data is in one table, but I want to split it into more entities.
Please note that:
I would not like to use discriminator column in the database
There isn't a column that I could use for #DiscriminatorFormula
I do not want to embed Beer inside BeerWithIngredients, because it essentially is not a composition, but proper inheritance
Is there a way of achieving this with JPA (Hibernate)? Right now it complains about missing discriminator column, that I don't plan to provide.
Introduce a new super class RootBeer with all common beer properties. Annotate this class with MappedSuperClass. Make Beer and BeerWithIngredients inherit from RootBeer and annotate them with Entity as well as Table(name="beer").
For an example check this.