I'm working on a legacy application and I was asked to integrate Hibernate (this is my first time working with it). This app has 3 tables (among others) as follows:
Table SITE Table PARAMS Table TRANS
========== ============== ===============
pk: id (INT) pk: p_id (INT) pk: t_id (INT)
lang_id (INT) name (CHAR) fk: p_id (INT)
value (INT) fk: lang_id (INT)
text (CHAR)
Then I need to get the parameters from PARAMS along with their translations, stored in TRANS, according to the language defined for the application, which is stored in SITE.
I've been struggling trying to understand how to make a join of the tables to get the data for the entity. I tried using #JoinTable, but I couldn't figure out how to make a 3-way join, so I started trying with #SecondaryTables without luck.
I defined this entity to map the requested data (I know this won't work as it is now) and I'm trying to figure out the proper way to make the join.
#Entity
#Table(name = "params")
#SecondaryTables(
{
#SecondaryTable(name = "trans", pkJoinColumns = #PrimaryKeyJoinColumn(name = "p_id")),
})
public class Tparam implements Serializable
{
#Id
#GeneratedValue
#Column(name = "p_id")
private int id;
#Column(name = "name")
private String Name;
#Column(name = "text")
private String visibleText
...
}
Any help is appreciated!
For reference, this SQL query gives me what I want:
SELECT * FROM params, lang, site WHERE params.p_id = lang.p_id AND lang.lang_id = site.lang_id;
You need to define 3 entities :
1-Param
2-Lang
3-Site
#Entity
#Table(name = "params")
public class Tparam implements Serializable
{
#Id
#GeneratedValue
#Column(name = "p_id")
private int id;
#Column(name = "name")
private String Name;
#Column(name = "text")
private String visibleText
...
}
#Entity
#Table(name = "lang")
public class Lang implements Serializable
{
#Id
#GeneratedValue
#Column(name = "lang_id")
private int id;
#ManyToOne
#JoinColumn(name = "p_id")
private Tparam param;
...
}
#Entity
#Table(name = "site")
public class Site implements Serializable
{
#Id
#GeneratedValue
#Column(name = "site_id")
private int id;
#ManyToOne
#JoinColumn(name = "lang_id")
private Lang lang
...
}
Then, when you need the data you can use Criteria (or Query) on Site entity to fetch data. Each record of site contains one Lang and each of them contains one Tparam.
Related
I would like to use the Foreign key "MODEL_ID" to retrieve just one column "MODEL_NAME" from the TT_CARS table,
I tried the following code, that works but it returns the whole CARS object.
#JoinColumn(name = "MODEL_ID", referencedColumnName = "ID")
#ManyToOne(fetch = FetchType.EAGER)
private CARS cars;
Also I tried the code below, its also not working
#SecondaryTable(name = "TT_CARS", pkJoinColumns = #PrimaryKeyJoinColumn(name = "ID", referencedColumnName="MODEL_ID"))
Is there other way to retieve just the column (MODEL_NAME) using hibernate and JPA??
remarks: The modelName should be part of the Options class.
my code
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
#Entity
#Table(name = "TT_OPTIONS")
public class Options {
#Id
#Column(name = "ID")
private String id;
#NotNull
#Column(name = "DESCRIPTION", nullable = false)
private String description;
#Column(name = "MODEL_ID") // Foreign key
private Long modelId;
#Column(name = "MODEL_NAME", table = "TT_CARS") // this is the column name I would like to retrieve from the TT_CARS table
private String modelName;
// getters and setters
}
You can use #Formula. It is read-only calculated column that can be retrieved by the custom subquery. It does not present in the target table.
Defines a formula (derived value) which is a SQL fragment that acts as
a #Column alternative in most cases. Represents read-only state.
Example:
#Entity
#Table(name = "TT_OPTIONS")
public class Options {
#Id
#Column(name = "ID")
private Long id;
#Column(name = "DESCRIPTION", nullable = false)
private String description;
#Column(name = "MODEL_ID")
private Long modelId;
#Formula("(select TT_CARS.MODEL_NAME from TT_CARS where TT_CARS.ID = MODEL_ID)")
private String modelNameFormula;
}
#Entity
#Table(name = "TT_CARS")
public class Cars {
#Id
#Column(name = "ID")
private Long id;
#Column(name = "MODEL_NAME")
private String modelName;
}
Hibernate generated native query:
select
options0_.id as id1_4_0_,
options0_.description as descript2_4_0_,
options0_.model_id as model_id3_4_0_,
(select
TT_CARS.MODEL_NAME
from
TT_CARS
where
TT_CARS.ID = options0_.MODEL_ID) as formula1_0_
from
tt_options options0_
where
options0_.id=?
#SecondaryTable designed for #OneToOne relationship to map multiple tables to the same entity. It will not work for the #ManyToOne relationship.
I am trying to get how to write the JPA method for the class by using its foreign key instead of the primary key. Like, here I can't use findById() method, as it finds records according to primary key defined in the class. Below are the two classes for #ManyToOne and #OneToMany.
PARENT CLASS :
#Entity
#Getter
#Setter
//#Data
#NoArgsConstructor
#Table(name = "financial_plan_details", schema = "financialplanadmin")
public class FinancialPlanDao {
// This internalId is the primary key of the table.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "internal_plan_id")
private int internalId;
// This stores the plan status into the database table.
#Column(name = "plan_status")
#Size(max = 10)
private String planStatus;
#Column(name = "presentation_file_key")
#Size(max = 500)
private String presentationFileKey;
#Column(name = "create_timestamp")
#NotNull
private Timestamp createdTimestamp;
#OneToMany(mappedBy = "financialPlan")
private List<FinancialSubPlan> subPlans;
}
CHILD CLASS:
#Entity
#Getter
#Setter
#NoArgsConstructor
#Table(name = "financial_plan_subplan", schema = "financialplanadmin")
#JsonInclude(Include.NON_NULL)
public class FinancialSubPlan {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "subplan_id")
private int subPlanId;
#Column(name = "external_subplan_id")
private String externalSubplanId;
#Column(name = "is_chosen")
private Boolean subPlanIsChosen;
#ManyToOne
#JoinColumn(name = "internal_plan_id")
private FinancialPlanDao financialPlan;
}
The table generated for FinancialSubPlan will consist of the primary key column "subplan_id" and foreign key column "Internal_plan_id". So is there any way to write the JPA method to get records of FinancialSubPlan by "internal_plan_id". Also how to get this using #Query ?
It would be something like this. IDE auto-suggest would help as you type, just in case.
findFinancialSubPlanByFinancialPlanDaoId(int internalId)
or
findFinancialSubPlanByFinancialPlanDao(int internalId)
I have a table PATIENT which has some fields. There's also a CONTACT table that has a field called 'patientId' that needs to store PATIENT's ID (which is autogenerated), and a PATIENT_CONTACT table that only relates the two tables.
Now, here comes the tricky part. There are three other tables: CONTACT_ADDRESS, CONTACT_PHONE, CONTACT_EMAIL. A row in CONTACT will have the same ID as one (and only one) of CONTACT_ADDRESS, CONTACT_PHONE and CONTACT EMAIL. How do I get this all to work?
I have tried so many approaches, this is what I have right now:
#Entity
#Table(name = "patient", schema = "patient")
public class PatientEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
//... more fields
#OneToOne
private ContactEmailEntity contactEmailEntity;
#OneToOne
private ContactAddressEntity contactAddressEntity;
#OneToOne
private ContactPhoneEntity contactPhoneEntity;
}
The three CONTACT_* classes are similar and they look like this:
#Table(name = "contact_address", schema = "patient")
public class ContactAddressEntity {
#Id
#Column(name = "id")
private Long id;
// ... more fields
#OneToOne(cascade = {CascadeType.ALL})
#MapsId
private ContactEntity contact;
}
And my CONTACT class looks like this:
#Table(name = "contacto", schema = "paciente")
public class ContactEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
//... more fields
Can you see things that don't look right or could be done better? I get all sorts of errors with every approach. My latest one is:
ERROR: column patientent0_.contact_address_entity_contact_id does not exist
when trying to do a simple patient find. Please, any help is appreciated!
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.
unfortunately I have a small understanding problem.
I'm trying to use JPA to create an inner join via 2 tables.
The situation:
Table: Projects
Fields:
ID (PK)
Name
Table: Users
Fields:
ID (PK)
username
password
Table: permissions
Fields:
ID (PK)
permissionName
Table: permissionsMapping (NO PK)
project_id (FK => projects.ID
user_id (FK => users.ID)
permission_id (FK => permissons.ID)
I need all projects that have at least one entry in the permissionsMapping table.
It is important to say that you are using it for logging in to the REST service OAuth2 so Users.ID = Current User should be set.
the Project Model:
public class ProjectModel
{
#Column(name = "ID", nullable = false)
private long ID;
#Column(name = "Name", nullable = false)
private String Name;
enter code here
#OneToMany(cascade=CascadeType.ALL, targetEntity=PermissionsMappingModel.class)
private Set<PermissionsMappingModel> permissionsMapping;
}
the permissionsMapping Model:
public class PermissionsMappingModel
{
#Column(name = "project_id", nullable = false)
private long project_id;
#Column(name = "user_id", nullable = false)
private long user_id;
#Column(name = "permission_id", nullable = false)
private long permission_id;
}
between ask
If I do not use an #Id anotation in permissionsMapping the service does > not start anymore because it says it misses the identifier. So how do I > tell him that the table has no primary key?
How do I connect that best now?
In the best case I get all the projects for the current user
In the first step, the permission would not be that important. It would be important that I get all projects for which there is an entry with the current user in the permissionsMapping table.
As I described it, I get the following error:
Caused by: org.hibernate.AnnotationException: Illegal attempt to map a
non collection as a #OneToMany, #ManyToMany or ...
I realize that this is probably the basics, but I do not quite understand it yet
Can anyone explain to me?
You need to use #EmbeddedId and #Embeddable annonations for defining you composite entity and key.
#Data #Entity #Table(name="Projects")
public class Projects {
#Id
private Long projectId;
private String projectName;
#OneToMany(mappedBy = "mappingId.projectId")
private Set<PermissionMapping> permissionMappings = new HashSet<PermissionMapping>();
}
#Data #Entity #Table(name="Users")
public class Users {
#Id
private Long userId;
private String userName;
private String password;
}
#Data #Entity #Table(name="Permissions")
public class Permissions {
#Id
private Long permissionId;
private String permissionName;
}
#Data #Entity #Table(name="PermissionMapping")
public class PermissionMapping {
#EmbeddedId
private PermissionMappingId mappingId;
#Embeddable
#Data
public static class PermissionMappingId implements Serializable{
private Long projectId;
private Long userId;
private Long permissionId;
}
}
For more reading:
1. EmbeddedId
2. Embeddable