JPA, Composite Key consisted of foreign key and table column members - java

Greetings to the community,
I am struggling all day to find a solution to the issue below.
The scenario is the following, I have a table
---TABLE_ONE---
INT ID
VARCHAR NAME
PRIMARY_KEY (ID)
and my other table consisted of three columns which consist together a composite key
---TABLE_TWO---
INT TABLE_ONE_ID (FK -> TABLE_ONE.ID)
VARCHAR NAME
VARCHAR EMAIL
PRIMARY_KEY(TABLE_ONE_ID, NAME, EMAIL)
The relationship I want to achieve is that the TABLE_ONE entity will
have a list of objects from the TABLE_TWO (one-to-many relationship).
I tried to do this with as shown below.
#Entity
#Table(name = "TABLE_ONE")
public class TableOne {
#Column(name="id")
private int id;
#Column(name="name")
private String name
#OneToMany(fetch = FetchType.EAGER, mappedBy = "tableOne")
private List<TableTwo> tableTwoList;
//getters, setters, constructors
}
#Entity
#Table(name = "TABLE_TWO")
public class TableTwo {
#EmbeddedId
private TableTwoCompositeId tableTwoCompositeId;
#ManyToOne
#JoinColumn(name = "TABLE_ONE_ID", referencedColumnName = "ID", insertable = false, updatable = false)
private TableOne tableOne;
//getters, setters, constructors
}
#Embeddable
public class TableTwoCompositeId {
#Column(name = "TABLE_ONE_ID")
public Integer provider;
#Column(name = "NAME")
public String name;
#Column(name = "EMAIL")
public String email;
//getters, setters, constructors
}
However, I'm getting javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet and Caused by: java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist when a TableOne object is retrieved from the database.
Thanks in advance for any help!

I think you need several minor changes:
TableOne.id needs an #Id annotation
The type of TableTwoCompositeId.provider should match the type of TableOne.id
TableTwo.tableOne needs a #MapsId annotation to indicate it maps TableTwoCompositeId.provider
Here is how the code should look:
#Entity
#Table(name = "TABLE_ONE")
public class TableOne {
#Id
#Column(name="id")
private int id;
#Column(name="name")
private String name
#OneToMany(fetch = FetchType.EAGER, mappedBy = "tableOne")
private List<TableTwo> tableTwoList;
//getters, setters, constructors
}
#Entity
#Table(name = "TABLE_TWO")
public class TableTwo {
#EmbeddedId
private TableTwoCompositeId tableTwoCompositeId;
#MapsId("provider") // maps provider attribute of embedded id
#ManyToOne
#JoinColumn(name = "TABLE_ONE_ID", referencedColumnName = "ID", insertable = false, updatable = false)
private TableOne tableOne;
//getters, setters, constructors
}
#Embeddable
public class TableTwoCompositeId {
#Column(name = "TABLE_ONE_ID")
public int provider;
#Column(name = "NAME")
public String name;
#Column(name = "EMAIL")
public String email;
//getters, setters, constructors
}

Related

How to retrieve ONE column from another table with Foreign key using Hibernate / JPA

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.

JPA hibernate ManyToOne relationship

I have 2 entities User and Venue. One user can have multiple venues. The table looks like this:
user_id is the foreign key in the Venue table.
I am trying to create a query for retrieving all Venues by user_id. This is what I have:
#Override
public List<Venue> findVenueByOwnerId(Long userId) {
return em.createQuery("select v from Venue v where v.user.id = :ownerId", Venue.class)
.setParameter("ownerId", userId)
.getResultList();
}
What am I doing wrong?
EDIT:
These are my mappings:
For User class:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
private String email;
private String username;
private String password;
private String firstName;
private String lastName;
#OneToMany
#JoinColumn(name = "user_id")
private List<Venue> venues;
For Venue class:
#Entity
public class Venue {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
private String name;
private String location;
private int capacity;
#ManyToOne
#Column(name = "user_id", updatable = false, nullable = false)
private User user;
And if I am trying to add getters and setters for the User in the Venue class, it throws me this error:
Caused by: org.hibernate.MappingException: Could not determine type for: razvan.sem3.project.model.User, at table: Venue, for columns: [org.hibernate.mapping.Column(user)]

Hibernate OneToOne Table join

Learning Hibernate.
I have the following classes User, Region, Country as follows
public class User {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(name = "first_name")
Private String firstName;
#Column(name = "last_name")
private String lastName;
#OneToOne(fetch = FetchType.EAGER)
#JoinTable(name = "user_country_region", joinColumns ={#JoinColumn(name = "user_id") }, inverseJoinColumns = { #JoinColumn(name = "country_id") })
private Country userCountry;
#OneToOne(fetch = FetchType.EAGER)
#JoinTable(name = "user_country_region", joinColumns = {#JoinColumn(name = "user_id") }, inverseJoinColumns = { #JoinColumn(name = "region_id") })
private Region userRegion;
//With its respective Getters and Setters
}
public class Country {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(name = "name")
private String name;
//With its respective Getters and Setters
}
public class Region {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(name = "name")
private String name;
//With its respective Getters and Setters
}
The problem am facing is hibernate query only returns region and not country. What could be causing this?
Tried getting country and region values as below
System.out.println("Country: "+user.getCountry().getName());
System.out.println("Region: "+user.getRegion().getName());
Response from Hibernate Show sql. Seems missing country details.
Hibernate:
select
this_.id as id1_3_3_,
this_.first_name as first_na2_3_3_,
this_.last_name as last_na3_3_3_,
region2_.id as id1_8_2_,
region2_.name as name2_8_2_
from
user this_
left outer join
user_country_region this_1_
on this_.id=this_1_.user_id
left outer join
region region2_
on this_1_.region_id=region2_.id
where
this_.id=?
It is an invalid mapping. I have this error with Hibernate 5 while create the schema by Hibernate.
org.hibernate.boot.spi.InFlightMetadataCollector$DuplicateSecondaryTableException:
Table with that name [user_country_region] already associated with entity
Anyway, if you can use this mapping with your Hibernate version, having such kind of mapping with a join table for two relations is error prone.
Just use this mapping to associate User with Country and Region by foreign key columns.
public class User {
#OneToOne
private Country country;
#OneToOne
private Region region;
}

#OneToOne relationship with additional constraint

Suppose, we have two entities, first one:
#Entity
#Table(name = "entitya")
public class EntityA {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private Long name;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private Set<EntityB> childEntities;
}
and the second:
#Entity
#Table(name = "entityb")
public class EntityB {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "master")
private Boolean master;
#ManyToOne
#JoinColumn(name = "parent")
private EntityA parent;
}
So far, so good. However underlying database tables and constrains enforce that for any entityA there can be only one EntityB with boolean field master set to true. I can extract it by adding following method to entityA:
public entityB getMasterChild() {
for(entityB ent : childEntities) {
if(ent.isMaster()) {
return ent;
}
}
}
The question is, can I create #OneToOne relationship in EntityA that can express that rule, so that entityA can have additional masterChild member of type entityB?
If I understood you correctly you want to create/define a relationship between two entities based on a value of some entity's property. The think is that relationship between entities is defined on entities count (how many entities can has the other entity) and not on some entity's property value.
However
If you really want to use #OneToOne mapping for masterChild I would recommend creating a separate table/entity for it. Once this is done, you can include this new MasterChild entity into EntityA and annotate it with #OneToOne.
Here is new MasterChild entity
#Entity
public class MasterChild extends EntityB{
#Id
#Column(name = "id")
private Long id;
}
Note that I have removed 'master' from EntityB as it is no longer needed
#Entity
#Table(name = "entityb")
public class EntityB {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#ManyToOne
#JoinColumn(name = "parent")
private EntityA parent;
}
And here is modified EntityA
#Entity
#Table(name = "entitya")
public class EntityA {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private Long name;
#OneToOne
private MasterChild master;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private Set<EntityB> childEntities;
}

Hibernate one-to-one, No row with the given identifier exists exception

I need a link between two entities, so I use a one-to-one
#Entity
#Table(name = "T_USER")
public class User implements Serializable {
#Id
#Column(name = "user_id")
private int userId;
#Column(name = "login")
private String login;
#OneToOne(optional = true)
#JoinColumn(name="login", referencedColumnName="person_id", nullable = true, insertable = false, updatable = false)
private Person person;
}
#Entity
#Table(name = "T_PERSON")
public class Person implements Serializable {
#Id
#Column(name = "person_id")
private String personId;
#Column(name = "pin")
private String pin;
}
If there is no item for a particulary PERSON in table T_USER, user.getPerson throw a exception:
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [packagename.com.entity.Person#scabriou]
But If I have reference between the 2 tables in the db, the getter works!
I can't say if this the best solution but you could use the #NotFound annotation. E.g.
#NotFound(action = NotFoundAction.IGNORE)
private Person person;
I believe person will remain null and the exception will not be thrown.

Categories

Resources