I am having a particular issue when trying to save a collection of objects with hibernate. It seems that when I have more than one object of the same type, hibernate fails to generate the identifier, so I get a org.hibernate.NonUniqueObjectException .
Example:
App1 --> urls
{strApplicationId:1;URLTypeEntity{strCode:1,strDescription:Reply},strURL:www.address1.com},
{strApplicationId:1;URLTypeEntity{strCode:1,strDescription:Reply},strURL:www.address2.com},
{strApplicationId:1;URLTypeEntity{strCode:2,strDescription:Home},strURL:www.address3.com}
If I do not have two URLs with the same URLTypeEntity on the collection, the error is not triggered
#Entity
#Table(name = "tbl_urls")
public class URLEntity
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="intCode")
private Integer intCode;
private String strApplicationID;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "intType", referencedColumnName = "intCode")
private URLTypeEntity objURLType;
private String strURL;
}
#Entity
#Table(name = "tbl_applications")
public class ApplicationEntity
{
#OneToMany(cascade = CascadeType.ALL, mappedBy = "strApplicationID")
private List<URLEntity> colURLs;
}
ApplicationEntity must also have an id.
The solution was changing the CascadeType from ALL To Merge
#OneToMany(cascade = CascadeType.ALL, mappedBy = "strApplicationID")
Changed To
#OneToMany(cascade = CascadeType.MERGE, mappedBy = "strApplicationID")
Related
I have entity object which has relationship with itself in two forms:
entity refer to list of that entities
entity refer to entity (mainOrder), which is superior current enitity
Java class for order:
#Entity
#Table(name = "shop_order")
public class ShopOrder {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", columnDefinition = "serial")
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "main_id",
nullable = true)
private ShopOrder mainOrder;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "id") // I am not sure here should be id or mainOrder
private Set<ShopOrder> subOrders = new HashSet<>();
// some others columns, and getters and setters
}
Can you tell me how to ensure that entity for cascade remove? I need if some order will be removed, also will be removed its suborders (it means orders which have set that removed order as mainOrder)
mappedBy is the attribute name in the class ShopOrder that is the back reference to ShopOrder.
Cascade can be defined in the annotation attribute cascade
#OneToMany(fetch = FetchType.LAZY, mappedBy = "mainOrder", cascade = CascadeType.REMOVE)
private Set<ShopOrder> subOrders = new HashSet<>();
Read more about Cascading in the Hibernate manual:
http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#pc-cascade
I am using Postgresql for my database and it contains a table called user and a table called friendship, which has 2 foreign keys userA_id and userB_id. I know how to use mappedBy to check for friendships based on userA_id but I am not sure how to check for userB_id. Is there a way to tell hibernate to check a user ID from user table with both of columns on friendship table?
EDIT: Here is the code I currently have.
#Entity
#Table(name = "users")
public class UserDB implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "userid", nullable=false)
public int userID; //not null
#OneToMany (targetEntity = FriendshipDB.class, mappedBy = "userA_ID", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
//#OneToMany (targetEntity = FriendshipDB.class, mappedBy = "userB_ID", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
public List<FriendshipDB> friends = new ArrayList<>();
}
#Entity
#Table(name = "friendships")
public class FriendshipDB implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "friendshipid", nullable = false)
private int friendshipID; //not null
#ManyToOne
#JoinColumn(name="usera_id")
private UserDB userA_ID; //not null
#ManyToOne
#JoinColumn(name = "userB_id")
private UserDB userB_ID;
}
I think this is very specific mapping but the only solution I know is to go with 2 association like this:
#OneToMany(mappedBy = "user1")
private Collection<User> usersByFirst;
#OneToMany(mappedBy = "user2")
private Collection<User> usersBySecond;
I have a error with Hibernate:
org.hibernate.AnnotationException: mappedBy reference
an unknown target entity property: ch.zkb.documenz.backend.model.Template.user
in ch.zkb.documenz.backend.model.User.templates
I have two Tables: User and Template, but in Template I need to use the id of the user in: createdBy, lockBy or lastUpdateBy, I think I have to use the #onetomany like in my example, but something it's incorrect, What is the best practice to do this then?
public class User implements Serializable {
#Id
#Column(name = "user_id", unique = true, nullable = false)
private Long id;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
private Set<Template> templates;
public class Template implements Serializable {
#Id
#Column(name = "template_id", unique = true, nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "createdBy")
private User createdBy;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "lastUpdateBy")
private User lastUpdateBy;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "lockBy")
private User lockBy;
EDIT, I have now a Problem with the Bidirectional LAZY load, I want to get the user wo created the template but I can't.. always is NULL, but in the DB is stored properly
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "createdBy")
private Set<Template> createdTemplates;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "createdBy", referencedColumnName = "user_id", nullable = false)
private User createdBy;
You schould map to your private keys seperately, then in an transient method you can merge them.
private Set<Template> templates = new HasSet<Template>();
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "createdBy")
private Set<Template> createdByTemplates;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "lastUpdateBy")
private Set<Template> lastUpdateByTemplates;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "lockBy")
private Set<Template> lockByTemplates;
#Transient
public Set<Template> getTemplates(){
if(getCreatedByTemplates() != null){
templates.addAll(getCreatedByTemplates());
}
if(getLockByTemplates() != null){
templates.addAll(getLockByTemplates());
}
if(getLastUpdateByTemplates() != null){
templates.addAll(getLastUpdateByTemplates());
}
return templates;
}
The exception message is clear about what doesn't work, the mappedBy must refer to the attribute name that you do have in the other entity,
in your Template entity there's no attribute named "user", try to remove the mappedBy.
I believe mapped by is looking for bean name "user" in Template.
public class User implements Serializable {
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
private Set<Template> templates;
public class Template implements Serializable {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private User user;
Change is variable name createdby to user in Template Class would help
Could you help to persist a Map when String is not the key of the Entity mapped?
For example:
class A {
#Id
long id;
String code;
}
class B {
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
#What magical combination of JPA annotations should I use here?!
Map<String,A> mapAByCode;
}
I've tried a lot of combinations of {#JoinTable,#MapKeyColumn,#JoinColumn,#JoinTable} annotations with no success and I'm going crazy...
Thanks!
Since you seem to want to map your entities using the A.code value, #MapKey is what you are after. #MapKey allows you to define the value within the reference to use as the key for the map. As the javadoc states, it is required to be unique though or you will run into problems.
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
#MapKey(name="code")
Map<String,A> mapAByCode;
It seems that the problem is related to other map I'm using in the same class:
#Entity
class A {
#Id
long id;
String code;
}
#Entity
class B {
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
#JoinTable(name = "B_MAPABYID", joinColumns = #JoinColumn(name = "B_ID"))
#MapKey(name="id")
Map<Long,A> mapAById;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
#JoinTable(name = "B_MAPABYCODE", joinColumns = #JoinColumn(name = "B_ID"))
#MapKey(name="code")
Map<String,A> mapAByCode;
}
This configuration is not working for me, but if I set mapAById as transient all works fine. Does it makes any sense for you?
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.