I have two entities. One is the parent (for which I have a projection) and the other entity has FK relation with the parent. My parent entity does "not" have bidirectional relationship (mappedBy).
How do I expose/get the child entity in the projection I have for the parent.
Here is how I want.
Parent:
public class EntityA implements java.io.Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "ENTITYAID", unique = true, nullable = false)
private Integer entityAID;
......
}
Child:
public class EntityB {
#EmbeddedId
private EntityBPk entityBPk;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ENTITYAID", referencedColumnName = "ENTITYAID",insertable=false,updatable=false)
private EntityA entityA;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ENTITYCID", referencedColumnName = "ENTITYCID",insertable=false,updatable=false)
private EntityC entityC;
#Column(name = "DUMMY")
private String dummy;
}
I want to access EntityB from EntityA's projection. Something like below.
Projection for EntityA:
#Projection(name = "projEntityA", types = { EntityA.class })
public interface EntityAProjection {
.....
Set<EntityB> getEntityBs();
}
Note:
But I don't have any reference of EntityB inside EntityA (since I don't want bidirectional relationship)
This may not be needed. But just FYI.
public class EntityBPk implements Serializable {
#Column(name = "ENTITYAID", nullable = false)
private Integer entityAID;
#Column(name = "ENTITYCID", nullable = false)
private Integer entityCId;
}
Thanks
Bharath
Related
I would like to ignore #OnetoMany field in my entity. fetch data need to get actual fields but don't want to fire query to dependent table. But deleting data from parent table needs deletion from dependent table
I have tried #Transient that ignores but the delete is also being ignored. Is there any other option to tell JPA not to fetch data from childs table when i call the parent entity?
#Entity
Table(name = "User")
public class UserEntity implements Serializable {
#Id
#Column(name = "id")
private int id;
#Column(name = "SERIAL", unique = true, nullable = false)
private String serial;
#OneToMany(mappedBy = "serialBySerialId", cascade = CascadeType.ALL)
private Set<UserActionEntity> userActionsById;
}
#Table(name = "user_action")
public class UserActionEntity implements Serializable {
#Id
#Column(name = "id")
private int id;
#Column(name = "action")
private String action;
#ManyToOne
#JoinColumn(name = "USER_ID", referencedColumnName = "ID", nullable = false)
private UserEntity userByUserId;
If you don't want to fire query to dependent table, you can use (fetch = FetchType.LAZY) on UserActionEntity property.
#OneToMany(mappedBy = "serialBySerialId", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<UserActionEntity> userActionsById;
Suppose we have entity A that contains a list of entities with type B (with lazy initialization).
Entity B has one BLOB field and some other, that doesn't contain much data.
How can I, using hibernate criteria query, get entity A with it's fields and each A-entity with list of Bs, but every B-entity without the BLOB field ?
Also, I do not want to extract As and iterate them to get Bs. (I now, how to use 'Projections' to extract just Bs with required fields).
Here is some code sample:
A-entity:
#Entity
#Table(name = "A")
public class A implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#OneToMany(mappedBy = "order", fetch = FetchType.LAZY)
#Cascade(CascadeType.ALL)
private List<B> list = new LinkedList<>();
}
B-entity:
#Entity
#Table(name = "B")
public class B implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "data", nullable = false)
#Lob
private byte[] data;
#ManyToOne(targetEntity = A.class, fetch = FetchType.EAGER)
#JoinColumn(name = "A_id", nullable = false)
private A a;
}
I have an existing data model that I'm very happy with:
public class Garden {
private String name; // "Oak Grove"
private List<Plant> plants;
}
public class Plant {
private String name; // "Cherry Tomato"
}
I would like to map this in Hibernate with the following conditions:
The Plant class in Java does not maintain a reference to its parent Garden. This makes things more difficult in the Java tier, IMO.
The PLANT table should have a GARDEN_ID column which is a foreign key to the GARDEN(ID) column.
My initial setup, prior to the #OneToMany addition:
#Entity(name = "GARDEN")
public class Garden {
#Id
#Column(name = "ID", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "NAME", nullable = false)
private String name; // "Oak Grove"
// Not yet mapped
private List<Plant> plants;
}
#Entity(name = "PLANT")
public class Plant {
#Id
#Column(name = "ID", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "NAME", nullable = false)
private String name; // "Cherry Tomato"
}
How can I define the #OneToMany annotation on the List<Plant> plants; in such a way that the foreign key reference is maintained in the Plant?
If I just add:
#OneToMany(cascade = { CascadeType.ALL })
#JoinColumn(name = "GARDEN_ID")
private List<Plant> plants;
Then saving a garden with a plant fails like so:
Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "GARDEN_ID"; SQL statement:
insert into PLANT (NAME, ID) values (?, ?) [23502-191]
So it seems Hibernate isn't trying to persist the foreign key. Is there a way to accomplish this without completely mucking up my object model?
Edit: The way I'm testing this is with:
Garden garden = new Garden("Oak Grove");
garden.addPlant(new Plant("Cherry Tomato"));
gardenManager.save(garden);
In which the save() method looks very Hibernate-ey:
public void save(T item) {
try (Session session = factory.openSession()) {
Transaction transaction = session.beginTransaction();
try {
session.saveOrUpdate(item);
transaction.commit();
} catch (Exception ex) {
System.out.println("Error occurred saving item: " + ex.getMessage());
ex.printStackTrace();
transaction.rollback();
}
}
}
Yogesh Sakurikar was close, but the bi-directional #JoinColumn was a bit off. Below you will see how to join bidirectionally or mono-riectionally
#Entity(name = "GARDEN")
public class Garden {
#Id
#Column(name = "ID", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "NAME", nullable = false)
private String name; // "Oak Grove"
// use this if you don't want a bi-directional relationship
// #OneToMany
// #JoinColumn(name = "ID", referencedColumnName="GARDEN_ID")
// private List<Plant> plants;
// use this if you want it bi-directional
#OneToMany(fetch = FetchType.LAZY, mappedBy = "garden")
private Set<Plant> plants;
}
#Entity(name = "PLANT")
public class Plant {
#Id
#Column(name = "ID", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "NAME", nullable = false)
private String name; // "Cherry Tomato"
// use this if you don't want a bi-directional relationship
// #Column(name="GARDEN_ID")
// private long gardenId;
// use this if you want a bi-directional relationship
#ManyToOne
#JoinColumn(name = "GARDEN_ID", referencedColumnName="ID", nullable = false)
private Garden garden;
}
The code below assumes bi-directional relationship. Otherwise you'd need to know your Garden.id before you could fully describe any child Plant
Garden garden = new Garden("Oak Grove");
Plant plant = new Plant("Cherry Tomato")
plant.setGarden(garden); //don't forget to set the parent on the child
garden.addPlant(plant);
gardenManager.save(garden);
For one to many relationship, if the plant will going to hold the relationship, you need to define it using bi-direction.
Here is I think you should be able to achieve it:
#Entity(name = "GARDEN")
public class Garden {
#Id
#Column(name = "ID", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "NAME", nullable = false)
private String name; // "Oak Grove"
#OneToMany(fetch = FetchType.LAZY, mappedBy = "garden")
private List<Plant> plants;
}
#Entity(name = "PLANT")
public class Plant {
#Id
#Column(name = "ID", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "NAME", nullable = false)
private String name; // "Cherry Tomato"
#ManyToOne
#JoinColumn(name = "GARDEN_ID", nullable = false)
Garden garden;
}
This bidirectional approach will let entity manager know that there exists a relationship between the two and since on one side it is one to many, for other side it become many to one. Hope this will help.
I am trying to create a bidirectional one-to-many association between two entities where the many side has a compound key. And one of the keys of the many side is coming from the one side. Also, I need to have the many side the owner of the association. Below is an example code showing what my code looks like.
Without Jointable
Parent Class which is the one side. I need to have this side owner of the association.
public class parent{
#Id
#Column(name = "NAME")
private String name;
#OneToMany(fetch=FetchType.LAZY)
#JoinColumns({
#JoinColumn(name="NAME", nullable = false),
#JoinColumn(name="PARENT", nullable = false)})
private Set<Child> childs;
}
Child Class which is the many side. Its primary key is "name" and "parent". "parent" is coming from the association.
public class child{
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name="parent", column=#Column(name="PARENT", nullable=false)),
#AttributeOverride(name="name", column=#Column(name="NAME", nullable=false))})
private ChildId id;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumns({
#JoinColumn(name="PARENT", nullable = false, updatable = false, insertable = false),
#JoinColumn(name="NAME", nullable = false, updatable = false, insertable = false)})
private Parent parent;
}
ChildId is the Embedded id.
#Embeddable
public class childId{
#Column(name = "PARENT")
private String parent;
#Column(name = "NAME")
private String name;
}
With Jointable
Parent Class
public class parent{
#Id
#Column(name = "NAME")
private String name;
#OneToMany(fetch = FetchType.LAZY)
#JoinTable(name="PARENTCHILD",
joinColumns= {#JoinColumn(name="PNAME", referencedColumnName = "NAME", nullable = false)},
inverseJoinColumns = {
#JoinColumn(name="CNAME", referencedColumnName = "NAME", nullable = false),
#JoinColumn(name="CPNAME", referencedColumnName = "PARENT", nullable = false)})
private Set<Child> childs;
}
Child Class
public class child{
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name="parent", column=#Column(name="PARENT", nullable=false)),
#AttributeOverride(name="name", column=#Column(name="NAME", nullable=false))})
private ChildId id;
#MapsId("parent")
#ManyToOne(fetch=FetchType.LAZY)
#JoinTable(name="PARENTCHILD",
inverseJoinColumns = {#JoinColumn(name="PNAME", referencedColumnName = "NAME", nullable = false)},
joinColumns = {
#JoinColumn(name="CNAME", referencedColumnName = "NAME", nullable = false),
#JoinColumn(name="CPNAME", referencedColumnName = "PARENT", nullable = false)})
private Parent parent;
}
Question1:
This code doesn't work. In case of "without jointable", it gives the below exception.
Caused by: org.hibernate.AnnotationException: A Foreign key refering com.entity.Parent from com.entity.Child has the wrong number of column. should be 1
Question2:
And in case of "with jointable", it gives below exception:
SQLCODE=-530, SQLSTATE=-23503, SQLERRMC=PARENTCHILD.FK_PARENTCHILD_CHILD
You don't need to keep Parent name as Id separately in Child , Hibernate will do that for you . I have made a simpler design .And you can control the relation by using mappedBy = childs ,in the #ManyToOne or mappedBy = parent in the #ManyToOne side.
#Entity
public class Parent{
#Id
private String name;
#OneToMany(fetch= FetchType.LAZY)
private Set<Child> childs;
public Parent(String name) {
this.name = name;
}
public Parent(){}
}
#Entity
public class Child{
#Id
private String name;
#ManyToOne(fetch=FetchType.LAZY)
private Parent parent;
}
Three tables will be generated by Hibernate
Child Table with columns name(Primary Key), parent_name(Foreign Key)
Parent Table with one column name(Primary Key)
Parent_child table with two columns parent_name and child_name
EDIT : Solution changed as per amir's needs, just add mappedBy whichever side you need to control the relationship.
#Entity
public class Child implements Serializable {
#Id
private String name;
#Id
#ManyToOne(fetch=FetchType.LAZY)
private Parent parent;
}
#Entity
public class Parent{
#Id
private String name;
#OneToMany(fetch= FetchType.LAZY)
private Set<Child> childs;
public Parent(String name) {
this.name = name;
}
public Parent(){}
}
EDIT - To name column in child side
#Id()
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="xyz")
private Parent parent;
To use One-To-Many bidirectional mapping using join table,use following code:
Parent Class
public class parent{
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
.....
.....
#OneToMany(cascade=CascadeType.ALL)
#JoinTable(name="Parent_Child", joinColumns={#JoinColumn(name ="parentId", referencedColumnName ="id")},
inverseJoinColumns={#JoinColumn(name ="childId", referencedColumnName ="id")})
private Set<Child> children;
.....
.....
}
Child Class
public class Child{
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
.....
.....
#OneToOne(cascade=CascadeType.ALL)
#JoinTable(name="Parent_Child", joinColumns={#JoinColumn(name ="childId", referencedColumnName ="id")},
inverseJoinColumns={#JoinColumn(name ="parentId", referencedColumnName ="id")})
private Parent parent;
.....
.....
}
Note that I have used OneTOMany mapping in Parent class - cause as per your logic a parent can have multiple children and I have used OneToOne mapping in Child class cause one child will have one parent(as mentioned in your requirements).
Hope this helps
I need CompanyUser.companyRolCompanyUsers property with OneToMany relation, completed in each query.
JPA company_usr entity:
#Entity
#Table(name = "company_usr")
public class CompanyUser extends BaseModel implements Serializable {
#Id
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(nullable = false)
private Company company;
#Id
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "usr_id", nullable = false)
private User user;
#Column(nullable = false)
private Boolean external;
#OneToMany(fetch = FetchType.EAGER)
private List<CompanyRolCompanyUser> companyRolCompanyUsers;
....
JPA companyRol_companyUsr entity:
#Entity
#Table(name = "companyRol_companyUsr")
public class CompanyRolCompanyUser extends BaseModel implements Serializable {
#Id
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name="companyuser_company_id", referencedColumnName="company_id"),
#JoinColumn(name="companyuser_usr_id", referencedColumnName="usr_id")
})
private CompanyUser companyUser;
#Id
#ManyToOne(fetch = FetchType.EAGER)
private CompanyRol companyRol;
....
How to set mappedBy in companyRolCompanyUsers property correctly?
If i get what you want to achieve i think you need something like :
#OneToMany(fetch = FetchType.EAGER, mappedBy="companyUser")
private List<CompanyRolCompanyUser> companyRolCompanyUsers;
You can have two properties for the same column like this :
#JoinColumn(name = "CGRADO_CODIGO", referencedColumnName = "CGRADO_CODIGO")
#ManyToOne
#NotFound(action=NotFoundAction.IGNORE)
private SipreGrado sipreGrado;
#Column(name = "CGRADO_CODIGO",insertable=false,updatable=false)
private String sipreGradoCodigo;
Remember if you have sometimes the entity NULL you can skip it with that annotation
#NotFound(action=NotFoundAction.IGNORE)
Also,Remember to set
insertable=false,updatable=false
for the one that you dont want to include in the insert/update queries.