For example i have
entities
#Entity
public class A{
#Id
Long Id;
...
}
#Entity
public class B{
#Id
Long Id;
...
}
#Entity
#IdClass(ABId.class).
public class AB{
#Id
#ManyToOne
private A a;
#Id
#ManyToOne
private B b;
private boolean state;
}
Class for composite primary key:
public ABId implements Serializable{
Long a;
Long b;
.........
}
and i want to get from class A something like this select * from AB ab where ab.a_id=1; ( id from A object)
i did such mapping in class A
#OneToMany(fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name="A_id", referencedColumnName="id"),
#JoinColumn(name="B_id", referencedColumnName="id")
})
List<AB> listAB;
but it does nothing i alawys get empty list.
Solved,
I did mapping
#OneToMany(fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name="A_id", referencedColumnName="id")
})
List<AB> listAB;
and it works like it should.
Related
Hi I have 3 entities.
#Entity
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
...
private List<BC> bcList;
}
#Entity
public class B {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
...
}
#Entity
public class C {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
...
}
These entities are linked by ManyToMany associations each other. It means I need an association table which look like a_b_c(id_a,id_b,id_c).
So I've created an AssociationOverrides which work exactly as I want.
#Embeddable
public class ABCPK implements Serializable {
#ManyToOne
#JoinColumn(name = "id_a")
private A a;
#ManyToOne
#JoinColumn(name = "id_b")
private B b;
#ManyToOne
#JoinColumn(name = "id_c")
private C c;
...
}
#Entity
#Table(name = "a_b_c")
#AssociationOverrides({
#AssociationOverride(name = "pk.a",
joinColumns = #JoinColumn(name = "id_a",referencedColumnName = "id")),
#AssociationOverride(name = "pk.b",
joinColumns = #JoinColumn(name = "id_b",referencedColumnName = "id")) ,
#AssociationOverride(name = "pk.c",
joinColumns = #JoinColumn(name = "id_c",referencedColumnName = "id")) })
public class ABC{
#EmbeddedId
private ABCPK pk=new ABCPK();
#Transient
public A getA() {
return pk.getA();
}
public void setA(A a) {
this.pk.setA(a);
}
...
}
public class BC{
private B b;
private List<C> cList;
}
However I would like to retrieve List bcList and List cList from my association table but I really don't know how can I do it. I've already tried #JoinFormula but I prefere to get it working using jpql only. Could you please put me in the right way ?
Thanks
Since I haven't got any help I've made up my mind to populate my map myself and re populate abcList before persist and update . However I really don't like this since it's not performance and memory friendly. (about 1*20*70 items in the abcList)
#Entity
public class A {
...
#OneToMany
private List<ABC> abcList;
private Map<B,List<C>> bcMap;
private Map<B,List<C>> buildBCmap(){
bcMap = new HashMap<>();
if(abcList!=null){
for(ABC abc:abcList){
if(! bcMap.containsKey(abc.getB()){
bcMap.put(abc.getB(),new ArrayList<>());
}
bcMap.get(abc.getB()).add(abc.getC());
}
}
return bcMap;
}
public Map<B,List<C>> getBcMap(){
if(bcMap==null){
buildBCmap();
}
return bcMap;
}
#PrePersist
#PreUpdate
public void buildAbcList(){
if(bcMap!=null){
abcList=new ArrayList<>();
for(B b: bcMap.keySet()){
for(C c: bcMap.get(b)){
abcList.add(new ABC(this,b,c));
}
}
}
}
}
Does anyone have a better or faster way to populate a map from associationOverride entity ?
Situation: Got Books and categories. Each category can have n books. Want to create new, update or delete books from category. If category is empty delete it from db. Currently insert, update, and delete books.
Problem: orphanRemoval=true doesn't delete category if it is empty.
#Entity
#Table(name = "book")
#Getter
#Setter
public class BookEntity implements DBEntity, Serializable {
#Id
private Integer id;
private String bookname;
#ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH, CascadeType.REFRESH})
#JoinColumn(name = "categoryid", referencedColumnName = "id")
private CategoryEntity categoryEntity;
public Integer getId() {
return this.id;
}
}
#Entity
#Table(name = "category")
#Getter
#Setter
public class CategoryEntity implements DBEntity, Serializable {
#Id
private Integer id;
private String categoryName;
#OneToMany(cascade = CascadeType.REMOVE, mappedBy = "categoryEntity", orphanRemoval = true)
private Set<BookEntity> bookEntitySet = new HashSet<BookEntity>(0);
}
#Transactional
public interface CategoryDAO extends CrudRepository<CategoryEntity, Integer> {
}
#Transactional
public interface BookDAO extends CrudRepository<BookEntity, Integer> {
}
Thanks for any help
p.s.
Tried:
didnt help:
Spring + JPA #OneToMany with orphanRemoval
looks stupid - deleting book from category (in case 2-n foreign key wont work):
https://hellokoding.com/jpa-one-to-many-relationship-mapping-example-with-spring-boot-maven-and-mysql/
Nothing mentioned:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/
I have 2 mapping classes (analogue to JPA classes):
AElement.java
#XmlType(propOrder = {"name", "children", })
#XmlRootElement(name = "a")
#XmlAccessorType( XmlAccessType.PROPERTY)
public class AElement implements Serializable {
private String name;
private List<BElement> children;
#XmlElement(name = "metadatum")
public List<BElement> getChildren(){
return children;
}
...
}
BElement.java
#XmlRootElement(name = "b")
#XmlType(propOrder = {"name"})
public class BElement implements Serializable{
private String name;
private AElement parent;
...
}
A and B are in a OneToMany relation. The XML should look like this:
<A>
<B></B>
<B></B>
</A>
If I unmarshal the xml, map it to my JPA classes and persist it to my database everything is
stored correctly except my references. This means that B is stored without a foreign key to A in the database.
I'm using JPA with Hibernate. Following my JPA classes:
A.java
#Entity
public class A implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column
private String name;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "parent")
private List<B> children;
public List<B> getChildren(){
return children;
}
...
}
B.java
#Entity
public class B implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column
private String name;
#ManyToOne(optional = true)
#JoinColumn(name = "a_id", referencedColumnName = "id")
private A parent;
...
}
Looks like I have to assign the appropriate A to each B. This solves my problem.
a.getB().forEach(b -> b.setA(a));
I don't know If it is a good workaround? Especially because I have other entities that are children of B.
Found a solution:
Method afterUnmarshal in class BElement.java
public void afterUnmarshal(Unmarshaller u, Object parent) {
this.a = (AElement)parent;
}
I have this error that i can not solve.
Exception Description: Problem compiling [SELECT e FROM ResourceGroup e WHERE e.aclUserResourceGroups.userGroup=:userGroup AND e.aclUserResourceGroups.canView=:canView].
[36, 69] The state field path 'e.aclUserResourceGroups.userGroup' cannot be resolved to a valid type.
[87, 118] The state field path 'e.aclUserResourceGroups.canView' cannot be resolved to a valid type.
NamedQuery:
SELECT e
FROM ResourceGroup e
WHERE e.aclUserResourceGroups.userGroup=:userGroup
AND e.aclUserResourceGroups.canView=:canView
ERD:
Entities:
#Entity
#Table(name="resource_group")
public class ResourceGroup implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(unique=true)
private String name;
#OneToMany(mappedBy = "resourceGroup", cascade = CascadeType.ALL, fetch=FetchType.LAZY, orphanRemoval=true)
#JoinColumn(name = "resourcegroup_id")
private List<UserGroupResourceGroup> aclUserResourceGroups;
}
Join entity:
#Entity
#Table(name="user_group_resource_group")
public class UserGroupResourceGroup implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#ManyToOne(targetEntity = UserGroup.class, cascade = CascadeType.PERSIST, fetch=FetchType.LAZY)
#JoinColumn(name="usergroup_id")
private UserGroup userGroup = new UserGroup();
#ManyToOne(targetEntity = ResourceGroup.class, cascade = CascadeType.PERSIST, fetch=FetchType.LAZY)
#JoinColumn(name="resourcegroup_id")
private ResourceGroup resourceGroup = new ResourceGroup()
}
UserGroups:
#Entity
#Table(name="user_group")
public class UserGroup implements Serializable{
#OneToMany(mappedBy="userGroup", fetch=FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "usergroup_id")
private List<AccessControlList> acl;
#OneToMany(mappedBy="userGroup", fetch=FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "usergroup_id")
private List<UserGroupResourceGroup> aclUserResourceGroups;
}
DAO:
#Override
public List<ResourceGroup> getAllowedResourceGroups(UserGroup userGrp){
return this.em.createNamedQuery("ResourceGroup.getAllCanView")
.setParameter("userGroup", userGrp)
.setParameter("canView", true)
.getResultList();
}
e.aclUserResourceGroups is a Collection and you cannot access it in that way.
Not tested, but try with something like this:
SELECT e
FROM ResourceGroup e
inner join e.aclUserResourceGroups acl
WHERE acl.userGroup=:userGroup
AND acl.canView=:canView
Hope this helps!
I have the following two classes, one ReqCandAssociation can have many Comments and it is mapped like so. I need to figure out a way that when I delete a ReqCandAssociation it deletes all of its associated comments. Thanks
#Entity
#Table(name = "candidate_jobReq")
public class ReqCandAssociation implements Serializable {
#Id
private Integer candidateId;
#Id
private Integer jobId;
#Column(name = "reqStatus")
private String reqStatus;
#ManyToOne
#PrimaryKeyJoinColumn(name="candidateId", referencedColumnName="id")
private Candidate candidate;
#ManyToOne
#PrimaryKeyJoinColumn(name="jobId", referencedColumnName="id")
private JobReq jobReq;
public ReqCandAssociation(){
}
Second class
#Entity
#Table(name="comment")
public class Comment {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column(name="commentText")
private String commentText;
#Column(name="commentDate")
private Date commentDate;
#ManyToOne
#PrimaryKeyJoinColumn(name="reqCandAssociationId", referencedColumnName="id")
private ReqCandAssociation reqCandAssociation;
#ManyToOne
#PrimaryKeyJoinColumn(name="userId", referencedColumnName="id")
private User user;
Change this to the following, i'm making it bidirectional mapping.
#Entity
#Table(name = "candidate_jobReq")
public class ReqCandAssociation implements Serializable {
#Id
private Integer candidateId;
#Id
private Integer jobId;
#Column(name = "reqStatus")
private String reqStatus;
#OneToMany(cascade = { CascadeType.ALL }) //this is added here.
#JoinColumn(name ="reqCandAssociationId")
private Set<Comment> comments;
-----
Readup more on the cascade options. All cascade types are all|none|save-update|delete|all-delete-orphan|delete-orphan
The cascade all will delete all the comments associated to this class.