How to get inheritance entity by using joined sub entity in jpa? - java

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.

Related

Spring JPA abstract/inheritance relationships

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.

How to store snapshot of a spring JPA entity in a new table with new primary key column

I have couple of entities, Person and PersonSnapshot. PersonSnapshot is same as Person, except for, it has its own primary key.
I would like use Java class hierarchy so that I need not redefine property names, but I am not able to get them to work as the two tables will have different "#Id" properties.
#Entity
#Table(name = "Person")
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
class Person {
#Id
private int id;
#name
private String name;
}
I need to store its snapshot as in
#Entity
#Table(name = "Person_Snapshot")
class PersonSnapshot extends Person {
#Id
private int snapShotId;
}
I don't want to create an abstract MappedSuperClass for common attributes as I will end up with 3 classes. Is there any way achieve the same result with just these two classes ?
Move everything that is common between the two classes into a superclass and annotate it with #MappedSuperclass. For more details see for example this: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html

Extend an entity class in JPA throws Unknown column 'DTYPE' in 'field list' error

#Entity
#Table(name = "PERSON")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class Person {
#Id
#GeneratedValue
#Column(name = "PERSON_ID")
private Long personId;
#Column(name = "FIRSTNAME")
private String firstname;
#Column(name = "LASTNAME")
private String lastname;
// Constructors and Getter/Setter methods,
}
Employee class extends Person
#Entity
public class Employee extends Person {
#Transient
private Date joiningDate;
// Copy Constructors and Getter/Setter methods,
}
The Employee class has only a transient object So I am not sure about using of #DiscriminatorColumn and #DiscriminatorValue, When i tried without using Discriminator that throws error
session.save(employee);
I am trying to save Employee object that throws Unknown column 'DTYPE' in 'field list' error
I have encountered the same issue using EclipseLink and I have tried to use #discriminator annotation ... without success
because in this solution, a specific column must be added in 2 tables.
I don't have the possibility to add columns in tables, so I have found following solution :
#Entity
#Table(name = "PERSON")
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Person {
I have just changed inheritance type from SINGLE_TABLE to TABLE_PER_CLASS
I have found useful explanation on Thoughts on Java
Just for information, my 2 tables are in reality 1 table and a view on same table with 2 or 3 joins.
You should use #DiscriminatorColumn and #DiscriminatorValue. You can find a good example here.
D_TYPE is basically name of your child class.
Let's suppose you have:
Abstract Employee(id, name);
class FullTimeEmployee extends Employee(Double salary)
with Inheritence.SINGLE_TABLE strategy.
A table employee will be created with these columns
Employee (D_TYPE, id, name, salary)
where D_TYPE will be name of your child classes.
employeeRepository.insert(Employee emp);
where you can pass emp as new FullTimeEmployee(id, name, salary);
After insert it will automatically populate d_type as Full_Time_Employee
If you want to change the name of D_TYPE column use
#DiscriminatorColumn(name="customizedNameofD_TYPE")
Just FYI: mostly used strategy is InheritanceType.JOINED
Persist child entity rather than persisting parent entity.
#MappedSuperclass
public class Person {
And
#Entity
#Table(name = "PERSON")
public class Employee extends Person {
This should resolve your issue.

JPA discriminator undesired

I know there are several questions on this argument, but I think mine is a bit different.
I'm trying to use JPA notation instead of XML mapping. In my queries always there's an undesired dtype column, and I don't want to use neither discriminator column and formula.
I have four classes as follow:
The first named ObjectUUID. All classes extend this super class.
This class is used only to define id field, as follow:
#MappedSuperclass
public class ObjectUUID {
#Id
#GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
protected String id;
// getter and setter and other static methods
}
Then I have another class, named TrackSys where I define other fields (as insert date and update date) as follow:
#MappedSuperclass
public class TrackSys extends ObjectUUID{
#Column(name="dt_ins")
private CustomCalendar dtInsert;
#Column(name="dt_upd")
private CustomCalendar dtUpdate;
// getter and setter
}
the third and the forth classes are beans mapped on DB, as follow:
#Entity
#Table(name="patient")
public class PatientUUID extends TrackSys {
}
#Entity
#Table(name="patient")
public class Patient extends PatientUUID {
#Column(name="surname")
private String surname;
#Column(name="name")
private String name;
#Column(name="cf")
private String cf;
// getter and setter
}
I define a repository to query my patient table, as follow:
public interface PatientRepository extends JpaRepository<Patient, Long> {
List<Patient> findBySurname(String surname);
}
When my Patient query runs, the generated SQL is the follow:
select patient0_.id as id2_2_, patient0_.dt_ins as dt_ins3_2_,
patient0_.dt_upd as dt_upd4_2_, patient0_.cf as cf7_2_,
patient0_.surname as surname8_2_, patient0_.name as name11_2_,
from patient patient0_ where patient0_.dtype='Patient'
and patient0_.surname=?
Now...
I don't want dtype column and I don't want to use discriminator formula.
With the XML mapping this is possible without particular properties to specify.
With JPA annotation I try in order:
Use #Inheritance(strategy = InheritanceType.SINGLE_TABLE) but dtype is always present
Use #Inheritance(strategy = InheritanceType.JOINED) but dtype is always present
Now, my feeling versus dtype is only hate, how can I get this simple query, as follow:
select patient0_.id as id2_2_, patient0_.dt_ins as dt_ins3_2_,
patient0_.dt_upd as dt_upd4_2_, patient0_.cf as cf7_2_,
patient0_.surname as surname8_2_, patient0_.name as name11_2_,
from patient patient0_ where patient0_.surname=?

How to select only specific fields using spring CrudRepository?

How can I select only specific fields from the following class hierarchy?
#Entity
public class MyEntity {
#Id private Long id;
#ManyToOne
#JoinColumn(name="fk_person_id", foreignKey = #ForeignKey(name="fk_person"))
private Person person; //unidirectional
private String fieldA, fieldB, ..field M;
//many more fields and some clobs
}
#Entity
public class Person {
#Id private Long id;
private String firstname;
private String lastname;
}
interface MyEntityRepository extends CrudRepository<MyEntity, Long> {
List<MyEntity> findByIdAndPersonFirstnameAndPersonLastname(long id, String firstname, String lastname);
}
This works perfectly, just the performance is very poor as MyEntity and also Person have some fields and associations that I would like to prevent to be fetched in this specific case (eg clob/texts).
Question: how can I write this query to find the result set, and just fetch the fields that are absolutely required (let's assume id, fieldA, fieldB from MyEntity?
Use lazy initialization for the non necessary fields:
FetchType.LAZY = Doesn’t load the relationships unless explicitly “asked for” via getter
FetchType.EAGER = Loads ALL relationships
For example, in Person:
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="fk_person_id", foreignKey = #ForeignKey(name="fk_person"))
private Person person; //unidirectional
Mark the unwanted fields as lazy (beware of this documented warning though), or create a dedicated class with the properties you want, and use projections in your query:
select new com.foo.bar.MyEntityWithFirstNameAndLastName(m.id, person.firstname, person.lastname)
from MyEntity m
join m.person person
where ...
If Person is an often-used entity, and contains large blobs that should rarely be fetched, you should consider storing the blobs in a separate entity, and use a OneToOne lazy association.

Categories

Resources