Hibernate Inheritance mapping issue - java

So, after several attempts of trying and trying to make this work the way I want, and of course checking different guide, I now come to you guys.
My program is designed to work like this:
persona (the father object)
-persona_cuil (pk on DB, generated by user)
empleado (persona's son)
-legajo_id (pk on DB, generated by program NOT DB (couldnt make that work either))
-persona_cuil (FK from persona)
empvarios (empleado's son)
-legajo_id (PK and FK from empleado)
Now, the database is mapped that way, and it works just fine, the problem seems to be that hibernate somewhere mixes the primary keys sent to each object, and instead of inserting a legajo_id in empvarios, it inserts a persona_cuil.
Code for clases:
persona:
#Entity
#Table(name = "persona")
#Inheritance(strategy = InheritanceType.JOINED)
public class persona implements Serializable {
private static final long serialVersionUID = 2847733720742959767L;
#Id
#Column(name="persona_cuil")
private String persona_cuil;
#Column(name="nombre")
private String nombre;
#Column(name="apellido")
private String apellido;
#Column(name="fecha_nac")
private String fecha_nac;
#Column(name="direccion")
private String direccion;
#Column(name="localidad")
private String localidad;
#Column(name="provincia")
private String provincia;
#Column(name="pais")
private String pais;
#Column(name="fecha_muerte")
private String fecha_muerte;
#Column(name="fecha_alta")
private String fecha_alta;
#Column(name="fecha_baja")
private String fecha_baja;
#Column(name="mail")
private String mail;
#Column(name="plan_id")
private int plan_id;
public persona (){
this.setPlan_id(0);
}
//Getters and Setters
}
empleado:
#Entity
#Table(name = "empleado")
#Inheritance(strategy = InheritanceType.JOINED)
#PrimaryKeyJoinColumn(name="persona_cuil")
public class empleado extends persona implements Serializable {
private static final long serialVersionUID = -7792000781951823557L;
#Column(name="legajo_id")
private int legajo_id;
public empleado(){
super();
int leg = SentenceManager.ultimoRegistro("empleado");
if (leg == 0){ //this works fine, it just searches the last registry, if it exists, i uses the next available number
this.setLegajo_id(1);
}
else {
this.setLegajo_id(leg+1);
}
}
//Getters and Setters
}
empvarios:
#Entity
#Table(name="empvarios")
#PrimaryKeyJoinColumn(name="legajo_id")
public class empvarios extends empleado implements Serializable, ToPersona{
private static final long serialVersionUID = -6327388765162454657L;
#Column(name="ocupacion_id")
int ocupacion_id;
public empvarios() {
super();
this.setLegajo_id(super.getLegajo_id());
}
//Getters and setters
}
Now, if I try to insert a new empleado into the database, it works just fine... BUT if I try to insert an empvarios, in the place where should be legajo_id, hibernate places the persona_cuil (I tested this by removing the FK restriction on the data base)
Images below:
(cant post images due reputation restriction :/)
https://www.dropbox.com/sh/mu5c797adlf7jiv/AACnd8mx7GriSyq5OMKoddRna?dl=0
There you have the 3 photos, the name of the files shows which table is each one.
Any ideas on whats going on?

The problem was that the data base was wrongly mapped.
If anyone has this problem then you will have to rethink the structure of the DB.
As seen in the example i gave above, the database should look like this:
persona:
persona_id (PK-autoincemental)
empleado:
persona_id (FK to persona)
legajo_id
empvarios:
persona_id (FK to persona)
ocupacion_id
The reason this works like this is because you cannot have different ids to depend different clases within the data base. On the program side it "can" work like that, but it the data base it has to be mapped differently.
Thanks!

Related

springboot with MongoDb ,Transient field return null

When i trying to do my RBAC job , I've made a class RolePermission like belows:
#Data
#AllArgsConstructor
#NoArgsConstructor
public class RolePermission extends BaseEntity{
private Long roleId;
private Long permissionId;
#Transient
private List<Permission> permissions;
public RolePermission(Long roleId,Long permissionId){
this.roleId = roleId;
this.permissionId = permissionId;
}
}
class Permission like belows
#AllArgsConstructor
#NoArgsConstructor
#Data
public class Permission extends BaseEntity{
public Permission(Long id, Long parentId, String name){
this.setId(id);
this.parentId = parentId;
this.name = name;
}
private String name;
private Long parentId;
private String url;
private String permission;
private Integer type;
private String icon;
private Integer status;
private Integer ord;
}
Here comes my test :
LookupOperation lookup = Aggregation.lookup("permission", "roleId", "_id", "permissions");
Aggregation aggregation = Aggregation.newAggregation(lookup);
AggregationResults<RolePermission> role_permission = mongoTemplate.aggregate(aggregation, "role_permission", RolePermission.class);
//AggregationResults<Map> role_permission = mongoTemplate.aggregate(aggregation, "role_permission", Map.class);
System.out.println(role_permission.getMappedResults());
//userService.getAllPermissions(u);
When I add #Transient , permissions comes to null
and When I remove #Transient,permissions comes back.
I don't wanna save permissions to MongoDB, so I add #Transient, is there any way i can draw the data back without saving it to the Database. Because I get the permissions data from a relationship collectionRolePermission,not itself.
The #Transient behaves similar to the transient keyword.
transient is used to denote that a field is not to be serialized (and therefore not saved in the database too).
#Transient is used to denote that a field should not persisted in database (but it is still serializable as java object).
Take look this baeldung tutorial for it: https://www.baeldung.com/jpa-transient-ignore-field
There is no way to draw the data back without saving it to the Database because it isn't persisted at all since it is what #Transient is used for.
To get the data back you have to persist it somewhere else, but the best place is in the database. If you don't want to persist it along with the other data, consider saving it in a sperate database. So, you could split user data and authentication/RBAC data.

Can Hibernate map subset of columns into an internal sub Pojo

I have the following Pojo:
#Entity
#Table(name = "USER")
class User {
#Id
private long id;
private String name;
private int age;
private long lastVisited;
private long lastPlayed;
private long lastPayed;
...
}
I would like somehow if possible to map the Pojo like this:
#Entity
#Table(name = "USER")
class User {
#Id
private long id;
private String name;
private int age;
#Embedded
private UserStatistics statistics;
...
}
#Embeddable
class UserStatistics {
private long lastVisited;
private long lastPlayed;
private long lastPayed;
}
BUT, I DON'T want to move the statistics columns into a new
USER_STATISTICS table and do #OneToOne mapping.
Is there a Hibernate trick I can use here?
Thanks!
What you did is already enough, Hibernate does not require you to define fields for all columns in your table. It's rather the other way around - all non-transient fields should be reflected as columns in the corresponding table either using name defined in #Column annotation or generated using a naming convention used in hibernate configuration.
The example you presented is sufficient and will work, but I wouldn't recommend it as you can have two entities mapping single row at the same time.

Implement one-to-one relationship in java

I came up with an example demonstrating the one-to-one relationship between Employee class and EmployeeDetail class:
public class Employee {
private Long empId;
private String name;
private EmployeeDetail employeeDetail;
//gettter and setter
}
public class EmployeeDetail{
private Long empDetailsId;
private String empFullName;
private String empMailId;
private Employee employee;
//getter and setter..
}
In the Employee class, there's an EmployeeDetail field, and in EmployeeDetail class, there's an Employee field. I understand that as each Employee has its own EmployeeDetail and each EmployeeDetail belongs to only one Employee, but there're 2 points that confuse me:
What if two or more Employees have the same EmployeeDetail (and vice versa)? Is there any way to handle this in Java code or I can only do that in a relational database management system?
In SQL, foreign keys (IDs) represent the relationship between two tables, but in the above example, they use class objects instead. Please help me explain that
In an one-to-one relation, an EmployeeDetail can only belong to one Employee. If an EmployeeDetail should be able to belong to multiple Employees you will need a Many-to-one relationship (Many Employees to one Employee Detail).
The reason the foreign keys are noted by class objects is that this is most likely a Hibernate example, which uses Java Objects for database management. (Even if it misses some annotation for a clear Hibernate example)
Here you can find an example about Hibernate and database relations
look at this ex :
#Entity
#Table(name="d_agent_auth")
public class AgentAuth implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int idAuth;
#NotNull
private String password;
private Date dateCreation;
#OneToOne
#JoinColumn(name="code_agent")
private Agent agent;
public AgentAuth() {
super();
}
}
there is two way a navigable one sens and two sens that's means in the agent class you will not find a key reference agentAuth or two sens means that's in the agent you will find it :
#Entity
#Table(name="d_agent")
public class Agent implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String codeAgent;
#ManyToMany(mappedBy="DAgents", cascade=CascadeType.MERGE)
private List<Profil> profil;
#OneToMany(mappedBy="DAgent")
private List<SuiviDossier> DSuiviDossiers;
#OneToMany(mappedBy="DAgent")
private List<SuiviLot> suiviLots;
#OneToMany(mappedBy="agent")
private List<Affectation> affecter;
public Agent() {
super();
}
}

How to put propper DBFLow annotation

I want to insert doctor object to database, how should I put annotations for properties?
I tried to do it with te code shown below.
But i don't know how to do it on list properties specializations and phoneNumbers.
#Table(databaseName = WMDatabase.NAME)
public class Doctor extends BaseModel{
#Column
#PrimaryKey
#Unique(unique = true)
private String doctorId;
#Column
private FullName fullName;
#Column
private String organizationId;
#Column What shuld i put here?????
private List<Specialization> specializations;
#Column What shuld i put here?????
private Contacts contacts;
}
Below are the classes I use for doctor attributes:
public class Contacts extends BaseModel {
private List<PhoneNumber> phoneNumbers;
private String email;
private String fax;
}
public class Specialization extends BaseModel {
#Column
#PrimaryKey
#Unique(unique = true)
private String doctorId;
#Unique(unique = true)
private String specializationName;
public String getSpecializationName() {
return specializationName;
}
public void setSpecializationName(String specializationName) {
this.specializationName = specializationName;
}
DBFlow is a relational database system (not a mongo-type key/value store) and doesn't support lists as columns, according to the doc here.
List : List columns are not supported and not generally proper for a relational database. However, you can get away with a non-generic List column via a TypeConverter. But again, avoid this if you can.
The documentation on relationships may help you refine the model to suit your needs.

JPA: Load list of values from another table

I've got 2 tables vehicle and vehicle_image. The vehicle table contains all master data of the vehicles and the vehicle_image table contains the meta information of the images and the Base64 encoded string of the image. On vehicle may have 0 or more images.
Now when I query the vehicle object I'd like the object to contain the information from the vehicle_image table.
I'm pretty new to JPA and the examples I could find always seem to read only one value from another table, not a list.
What would be the simplest way of adding an attribute to the vehicle object that contains the image data?
#Entity
#XmlRootElement(name = "vehicle")
public class Vehicle {
#Id
private String vin;
private String commission;
#Column(name="swiss_type_number")
private String swissTypeNumber;
#Column(name="sale_type")
private String saleType;
#Column(name="exterior_color")
private String exteriorColor;
#Column(name="interior_color")
private String interiorColor;
private String remarks;
#Column(name="additional_title")
private String additionalTitle;
#Column(name="added_value_description")
private String addedValueDescription;
#Column(name="first_registration")
private String firstRegistration;
private String guaranty;
#Column(name="last_inspection")
private String lastInspection;
private int dealer;
private int mileage;
private int price;
private int seats;
#Column(name="model_year")
private int modelYear;
#Column(name="car_damaged_in_accident")
private boolean carDamagedInAccident;
private boolean imported;
// List of images
List<VehicleImage> vehicleImages; // Something like this would be nice
}
JPA supports associations between entities. The one you need is #OneToMany
If your vehicle_image' table contains columnvehicle_idyou will need following mapping inVehicle` class:
#Entity
#Table(name = "VEHICLE")
#XmlRootElement(name = "vehicle")
public class Vehicle {
// other fields here
#OneToMany(mappedBy = "vehicle")
Set<VehicleImage> vehicleImages;
}
And also this in VehicleImage
#Entity
#Table(name = "VEHICLE_IMAGE")
public class VehicleImage{
// other fields here
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinColumn(name="VEHICLE_ID", referencedColumnName = "ID")
Vehicle vehicle;
}
Also you should better use Set for collections mapping in JPA, but it is a different topic
What you have here is a one-to-may relationship, you can use:
#OneToMany
List<VehicleImage> vehicleImages;
Refere to the javadoc for the attributes it may take and add them according to your table definitions.
Here you can find some examples of how to use it.

Categories

Resources