Specific kind of relation in hibernate - java

For example, I've got a table A with structure:
int id | int ref_id | varchar name
0 - hello
1 0 world
And entity class:
#Entity
#Table(name = "mypack.A")
public class A
{
#Id
#Column(name = "ID")
private int id;
#Column(name = "REF_ID", nullable=true)
private int ref_id;
#Column(name = "NAME")
private String name;
// getters and setters
}
Row with id 1 refers to row with id 0. How can I do this kind of relation using Hibernate? I have an idea to create A class object inside that. Is it ok?

You can use instead of the property ref_id of type int use a reference to another A object.
#Entity
#Table(name = "mypack.A")
public class A implements Serializable {
#Id
#GeneratedValue
#Column(name = "ID")
private Long id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "REF_ID")
private A refA;
#Column(name = "NAME")
private String name;
// getters and setters
}

Related

Jpa, linked class take main class id

I have a Product :
#Data
#Entity
#Table(name = "products", schema = "laboratory", catalog = "laboratory")
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class Product {
#Id
#GeneratedValue
private int id;
#ManyToOne(fetch = FetchType.LAZY, cascade= CascadeType.ALL)
#JoinColumn(name = "project_id")
#Transient
private Project project; // this one is for read only
#Column(name="project_id") // this will save the id in db for the project
private int projectId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="id")
private Inspection inspection;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="id")
private Information information;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="id")
private Departure departure;
private String un;
private String tc;
}
There is 3 class that this product needs in order to be a Product : Information, Inpection, Departure
All 3 of these classes are similar.
I want to link them by the Product.id witch is a #GeneratedValue AI in sql.
Here is one of the 3 class :
Information
#Data
#Entity
#Table(name = "products_informations", schema = "laboratory", catalog = "laboratory")
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class Information {
#Id
private int productId;
private String description;
private String model;
private int year;
private String serialNumber;
private int odometre;
private int noCrochet;
private int nbKeys;
private String localisation;
private String cemeteryPosition;
#JsonFormat(pattern = "yyyy-MM-dd")
private Date receptionDate;
}
I want, WHEN I save() the product, that the private String productId in this class to automatically take the Id from the Product class without having to do it manually in my controller.
You have the mappings backwards in your model.
By using
public class Product {
#Id
#GeneratedValue
private int id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="id")
private Information information;
You've told JPA to use the PRODUCT.ID primary key as a foreign key to the Information table; foreign keys are controlled by the relationship, so it means your ID value is pulled from the information.productId value. Opposite of what you are asking for and it means you have 4 mappings trying to set the PRODUCT.ID column value (set them different and see for yourself).
Try this instead:
public class Product {
#Id
#GeneratedValue
private int id;
#OneToOne(mappedby="product", cascade = CascadeType.ALL)
private Information information;
..
}
public class Information {
#Id
private int productId;
#MapsId
private Product product;
..
}
With this you will need to set the Information.product reference, but JPA will use that to set your productId value, using the one you set within the product.id property. You just need to set this relationship when you add an Information instance to a product. Do the same for the other relationships

How to set Id of one entity to the Id of another entity using JPA?

I'm new at Spring Boot's JPA concept so need your help in deciding how to import just the ID of another entity, say User into HealthData entity. Following is my User entity:
#Entity
#Table(name = "user",uniqueConstraints = {#UniqueConstraint(columnNames = "email")})
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String name;
#Email
#Column(nullable = false)
private String email;
private String imageUrl;
#Column(nullable = false)
private Boolean emailVerified=false;
#JsonIgnore
private String password;
#NonNull
#Enumerated(EnumType.STRING)
private AuthProvider authProvider;
private String providerId;
}
And I wish to define HealthData entity in the following manner :
#Entity
#Table(name = "HealthData",uniqueConstraints = {#UniqueConstraint(columnNames = "id")})
public class HealthData {
#Id
private Long id; //how to import id of User here?
#Column
private Double height;
#Column
private Double weight;
#Column
private int age;
...other columns
}
Now, I wish to use Id of User to this entity(kind of making parent-child relationship) . I don't want to add User class object in HealthData. I thought of using #OneToOne in HealthData but then it would add User in it. How can i just include Id from parent table in child table?
In this case, your HealthData has a reference to User, and I'm not sure why you wouldn't have mapped this as a foreign key. If you are able to do so, I'd suggest the following:
#Entity
#Table(name = "HealthData")
public class HealthData {
#Id
#OneToOne
#JoinColumn(name = "id")
private User user;
#Column
private Double height;
#Column
private Double weight;
#Column
private int age;
...other columns
}
JPA then handled setting the "ID" to the value within your user instance for you, and can persist both in the same transaction automatically. Allowing references to be marked as IDs is known as a derived ID and supported I believe since JPA 2.0.
As for efficiency, you can still lazy fetch or even not fetch the user instance. It is simple to just map the ID column as a basic using a slightly different approach:
#Entity
#Table(name = "HealthData")
public class HealthData {
#Id
private Long id;
#MapsId
#OneToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "id")
private User user;
#Column
private Double height;
#Column
private Double weight;
#Column
private int age;
...other columns
}
JPA will set both the User id as well as the healthData.id values based on what it generates for the user Id sequence when you set the healthData.user reference.
You can use getters and setters to set the value of user id in the healthdata table.

Hibernate: How to join attribute with condition using a third table

I have the following tables ...
Object1
-------
id
...
Object2
-------
id
...
AttributeValue
--------------
id
attribute_id
object_id
value
Attribute
---------
id
name
type
... and entity classes
#Entity
#Table(name = "Attribute")
public class Attribute {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "type")
private String type;
}
#Entity
#Table(name = "AttributeValue")
public class AttributeValue {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "attribute_id")
private Long attributeId;
#Column(name = "object_id")
private Long objectId;
#Column(name = "value")
private String value;
}
#Entity
#Table(name = "Object1")
public class Object1 {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// ...
// how to annotate to get all matching attribute values?
private Set<AttributeValue> values;
}
I want hibernate to fill the values instance variable with all AttributeValues that have the corresponding object_id and an attribute type of object1.
If it was only about the criterium of object_id, I would write e.g.
#JoinColumn(insertable = false, updatable = false, name = "object_id")
private Set<AttributeValue> values;
But in this case it would fill in also the values with type object2etc.
So my question is: Is this semantic expressible in Hibernate and if so, how?
EDIT: I want to highlight that the goal is to have multiple Objects (here Object1, Object2, ... ObjectN) that have no common hierarchy, but all share the feature of having attributes. The attributes for all objects will reside in one table, distinguished by some sort of discriminator (here exemplarily type).
I think the object must be:
#Entity
#Table(name = "AttributeValue")
public class AttributeValue {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "attribute_id")
private Long attributeId;
#ManyToOne
    #JoinColumn(name="object_id", nullable=false)
private Object1 object1;
#Column(name = "value")
private String value;
}
#Entity
#Table(name = "Object1")
public class Object1 {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(mappedBy="object1")
private Set<AttributeValue> values;
}
Hibernate will be generate only object_id column on AttributeValue table.

Mapping a database view entity with a simple entity and pass to DTO using Spring Data

I'm just learning Spring Data. I want to map a database view Entity with a simple Entity and pass to DTO which will contain columns both entities. I understand that I can use a special database view but I need to map precisely entities of Spring Data.
I have a database view Entity "MentorStudents":
#Entity
#Table(name = "mentor_students")
#Immutable
public class MentorStudents implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "mentor_id", updatable = false, nullable = false)
private Long mentorId;
//This entity I need to map
private Mentor mentor;
#Column(name = "active_students")
private Integer activeStudents;
public MentorStudents() {
}
//getters, setters, equals, hashCode
}
A database view sql of an above entity is:
SELECT id AS mentor_id, active_students
FROM mentor
LEFT JOIN ( SELECT mentor_id, count(mentor_id) AS active_students
FROM contract
WHERE close_type IS NULL
GROUP BY mentor_id) active ON mentor.id = active.mentor_id
ORDER BY mentor.id;
And I have a simple Entity "Mentor":
#Entity
#Table(name = "mentor")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Mentor implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Column(name = "first_name", nullable = false)
private String firstName;
#NotNull
#Column(name = "last_name", nullable = false)
private String lastName;
#Column(name = "patronymic")
private String patronymic;
#Column(name = "phone")
private String phone;
#NotNull
#Column(name = "email", nullable = false)
private String email;
#Column(name = "skype")
private String skype;
#Column(name = "country")
private String country;
#Column(name = "city")
private String city;
#Column(name = "max_students")
private Long maxStudents;
//getters, setters, equals, hashCode
I have to get a DTO which contains all Mentor fields and an "activeStudents" MentorStudents field without a "mentorId" field. How do it?
Use spring data projection:
public interface YourDto {
// all Mentor get fields
String getFirstName();
...
// activeStudents get field
Integer getActiveStudents();
}
public interface YourRepository extends JpaRepository<YourEntity, Integer> {
#Query(value = "select ...(all fields match YourDto) from Mentor m, MentorStudents s where m.id = s.mentorId and m.id = ?1")
Optional<YourDto> findMyDto(Integer mentorId);
}

Join two tables with hibernate

I am looking to create a DAO which represents a join of two tables with Java Hibernate. Here is the SQL I'd like to represent (Postgres 9.6 incase that matters):
SELECT tableOneValue, tableTwoValue
FROM table_one, table_two
WHERE table_one_filter = 2 AND table_one_id = table_two_id;
These tables have a OneToOne relationship.
Table1.java
#Entity
#Data
#Table(name="table_one")
public class TableOneDao implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "table_one_id")
private int tableOneId;
#Column(name = "table_one_value")
private String tableOneValue;
#Column(name = "table_one_filter")
private int tableOneFilter;
}
Table2.java
#Entity
#Data
#Table(name="table_two")
public class TableTwoDao implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "table_twp_id")
private int tableTwpId;
#Column(name = "table_two_value")
private String tableTwoValue;
}
I'm very new to hibernate so maybe this isn't the right way to think with it. What I would love to do is define a SomeDao class where I can do: daoManager.findAll(SomeDao.class, Pair.of("tableOneFilter", 2));
This would return a List<SomeDao> where we get all the rows that satisfy tableOneFilter == 2.
You need to use the #OneToOne and #JoinColumn annotation.
Pay special attention to the userDetail attribute mapping.
For example, the user class:
#Entity
#Table(name = "USERS")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USR_ID")
private long id;
#Column(name = "USERNAME", nullable = false, unique = true)
private String username;
#Column(name = "PASSWORD")
private String password;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="USR_DET_ID")
private UserDetail userDetail;
// Add Constructor, Setter and Getter methods
}
And this user details class:
#Entity
#Table(name = "USER_DETAILS")
public class UserDetail {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USR_DET_ID")
private long id;
#Column(name = "FIRST_NAME")
private String firstName;
#Column(name = "LAST_NAME")
private String lastName;
#Column(name = "EMAIL")
private String email;
#Column(name = "DBO")
private LocalDate dob;
// Add Constructor, Setter and Getter methods
}
Check the full code here.
Here is a JPA query which will work with your existing entity structure with the latest version of hibernate.
SELECT t1.tableOneValue, t2.tableTwoValue
FROM TableOneDao AS t1 JOIN TableTwoDao AS t2 ON t1.table_one_id = t2.table_two_id
WHERE t1.table_one_filter = ?
You can write a JPQL statement which is much better. Here is the sample solution:
SELECT NEW com.test.package.dao(t1.valueOne, t2.valueTwo)
FROM table_one t1 JOIN table_two t2
WHERE t1.filter = 2 AND t1.id = t2.id;
Please refer to this link and jump to the section where it mentions Result Classes (Constructor Expressions). Hope it helps. Thanks.

Categories

Resources