I have two classes, monitoringExpression and reportTrigger, with a one-to-many relationship. Hibernate is attempting to persist duplicate reportTriggers from the collection held by the monitoringExpression class. The first insert into the reportTrigger collection works, but subsequent inserts fail with a unique constraint violation because hibernate tries to persist the same reportTrigger twice. This is quite similar to a known hibernate bug (Hibernate inserts duplicates into a #OneToMany collection); however, in this case, we are not using a lazy collection. Here is the relevant code:
MonitoringExpression.Class
#Audited
#Entity
#Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class MonitoringExpression extends GeneratedIdXmlObject{
private String name;
private DeterminantDefinition determinantDefinition;
private String valueExpression;
private String testExpression;
private String messageExpression;
private String messageSeverity;
private boolean setExitStatusWhenTrue;
protected SortedSet<MonitoringExpressionAttribute> attributes = new TreeSet<MonitoringExpressionAttribute>();
private String color;
private Set<ReportTrigger> reportTriggers = new HashSet<ReportTrigger>();
.
.
.
#OneToMany(mappedBy="monitoringExpression",orphanRemoval=true,cascade={CascadeType.ALL},fetch=FetchType.EAGER)
#Sort(type=SortType.NATURAL)
#Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public SortedSet<MonitoringExpressionAttribute> getAttributes() {
return attributes;
}
public void setAttributes(SortedSet<MonitoringExpressionAttribute> attributes) {
this.attributes = attributes;
}
ReportTrigger.Class
#Audited
#Table(name="ReportTrigger")
#Entity
#Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class ReportTrigger extends GeneratedIdXmlObject{
private String name;
private String description;
private TriggerableReport report;
private Frequency burstPeriodSize;
private String periodStartExpression;
private String periodEndExpression;
private Set<ReportTriggerParameterMapping> parameterMappings = new HashSet<ReportTriggerParameterMapping>();
private MonitoringExpression monitoringExpression;
#XmlIDREF
#ManyToOne
#Audited
#GraphProcessorOverride(process=false,recurse=false)
#NaturalId(mutable=true)
public TriggerableReport getReport() {
return report;
}
public void setReport(TriggerableReport report) {
this.report = report;
}
#Embedded
public Frequency getBurstPeriodSize() {
return burstPeriodSize;
}
public void setBurstPeriodSize(Frequency burstPeriodSize) {
this.burstPeriodSize = burstPeriodSize;
}
#Audited
#OneToMany(mappedBy="reportTrigger",orphanRemoval=true,cascade={CascadeType.ALL})
#Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public Set<ReportTriggerParameterMapping> getParameterMappings() {
return parameterMappings;
}
.
.
.
#XmlIDREF
#ManyToOne
#GraphProcessorOverride(process=false,recurse=false)
#NaturalId(mutable=true)
public MonitoringExpression getMonitoringExpression() {
return monitoringExpression;
}
public void setMonitoringExpression(MonitoringExpression monitoringExpression) {
this.monitoringExpression = monitoringExpression;
}
As far as I can tell, we're not doing anything out of the ordinary to the reportTrigger collection (and we obviously cannot be adding the same tigger twice to a set). Has anyone seen anything like this? Thanks
Hibernate 3.6.10
Java 8
I think can do some checking as below
- Check unique constraint violation error you got is on which field ? It can be on Primary key column but also can any unique columns.
- If the violation is with your primary key then while your collection is a set then it can be 2 different TriggerableReport but share the same key value.
Related
I'm strugling with JPA. I tried several things but I can't figure out the right way to put the annotations.
What is want is like an Order/OrderLine relationship.
Thus:
Order( PK=orderId, fields=[...])
OrderLine (Pk1=orderId,Pk2=orderLineId, fields=[...])
Obviously, OrderLine.orderId refers to the 'Order' table.
What I functionally want to do is at least:
retrieve the Order with and without all orderlines. It should have a Set
retrieve an orderline by full PK, but without the associated Order.
retrieve a list of orderlines by orderId.
I only want these 2 tables and classes. nothing more nothing less.
I tried several things. Can anybody help me out with putting in the right annotations and members on these two classes?
Edit: what i've done so far.
Note that in this real example User=Order and UserRun=OrderLine. So, i am not interested in a seperate 'Run'-entity. Merely a UserRun as described by the Orderline.
#Entity
#Table(name = "user_runs")
public class UserRun {
#EmbeddedId
private UserRunKey id;
public UserRun(){};
public UserRun(String userName, String runUuid) {
this.id = new UserRunKey(userName, runUuid);
}
public String getUserName() {
return this.id.getUserName();
}
public String getRunUuid() {
return this.id.getRunUuid();
}
}
#Embeddable
class UserRunKey implements Serializable {
#Column(name = "username")
private String userName;
#Column(name = "run_uuid")
private String runUuid;
public UserRunKey(){};
public UserRunKey(String userName, String runUuid) {
this.runUuid = runUuid;
this.userName = userName;
}
public String getUserName() {
return userName;
}
public String getRunUuid() {
return runUuid;
}
}
This created a userruns/orderline table with the PK in the wrong way:
create table user_runs (run_uuid varchar(255) not null, username varchar(255) not null, primary key (run_uuid, username))
I want the primary key in reverse.
I want username as FK to User
I want a Set in my User-class.
When I do the following in my User-class:
#OneToMany
private Set<UserRun> userRuns;
It will create a
create table user_user_runs (user_username varchar(255) not null, user_runs_run_uuid varchar(255) not null, user_runs_username varchar(255) not null, primary key (user_username, user_runs_run_uuid, user_runs_username))
And that's something I definitely don't want! Once again, I don't want a Run-object (same as nobody's interested in a Line-class, from OrderLine)
I think I figured it out.
The UserRun/Orderline class:
#Entity
#Table(name = "user_runs")
public class UserRun {
#EmbeddedId
private UserRunKey id;
public UserRun(){};
public UserRun(String userName, String runUuid) {
this.id = new UserRunKey(userName, runUuid);
}
public String getUserName() {
return this.id.getUserName();
}
public String getRunUuid() {
return this.id.getRunUuid();
}
}
#Embeddable
class UserRunKey implements Serializable {
#Column(name = "username")
private String userName;
#Column(name = "run_uuid")
private String zrunUuid; //starts with a z, so the PK will be pk(username,run_uuid). Apparently, order in PK is determined from the variable names (alphabetic order)....
public UserRunKey(){};
public UserRunKey(String userName, String zrunUuid) {
this.zrunUuid = zrunUuid;
this.userName = userName;
}
public String getUserName() {
return userName;
}
public String getRunUuid() {
return zrunUuid;
}
}
In the userclass:
#OneToMany(mappedBy = "id.userName", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Set<UserRun> userRuns;
Unfortunately, there are 2 downsides:
I see that there are 2 queries executed instead of a Join on username. One to retrieve user, and 1 to retrieve the Set...
I needed to alter variablenames of the PK (compound/Embeddable). It seems there is no clean way to define the PK order. (Seriously?). Fortunately, the variable name is private, and not exposed by getter.
If anybody knows a cleaner way for these 2 issues. Let me know!
I think what you have to do is the following:
Because the primary key is compound key you need an ID class, as you already did:
#Embeddable
class OrderLinePK implements Serializable {
// you can use physical mapping annotations such as #Column here
#Column(name="...")
private Integer orderLineID;
// This is foreign key and the physical mapping should be done
// on the entity, and not here
private Integer orderID;
public OrderLinePK(){}
// getters + setters
// orverride equals() and hashCode() methods
}
Implement OrderLine entity
#Entity
public class OrderLine {
#EmbededId private OrderLinePK id;
#Mapsid("orderID")
#ManyToOne
#JoinColumn(name = "ORDER_ID", referencedColumn="ID")
private Order order;
// getters + setters ....
}
And the Order entity:
#Entity
public class Order {
#Id
private Integer id;
#OneToMany(fetch = FetchType.LAZY) // actually default by 1-to-n
private Coolection<OrderLine> orderLines;
// getters + setters ....
}
I did a #ManyToMany relationship in Hibernate with an extra column successfully, as follows.
Activity.class
#Entity
#Table(name = "Activity")
public class Activity {
#Id
#GeneratedValue
private int actId;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.activity",
cascade = { CascadeType.ALL, CascadeType.REMOVE })
private Set<ActivityRepairMap> activityRepairMaps = new HashSet<ActivityRepairMap>();
#NotEmpty
private String actTurno;
#NotEmpty
private String actTexto;
private String actFhc;
public Activity() {
}
// Getters and Setters
}
Repair.class
#Entity
#Table(name = "Repair2")
public class Repair {
#Id
#GeneratedValue
private int repId;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.repair")
private Set<ActivityRepairMap> activityRepairMaps = new HashSet<ActivityRepairMap>();
#NotEmpty(message=Constants.EMPTY_FIELD)
private String repNombre;
private Integer repCant;
public Repair() {
}
// Getters and Setters
}
ActivityRepairMap.class
#Entity
#Table(name="ActivityRepairMap")
#AssociationOverrides({
#AssociationOverride(name="pk.activity", joinColumns=#JoinColumn(name="actId")),
#AssociationOverride(name="pk.repair", joinColumns=#JoinColumn(name="repId"))
})
public class ActivityRepairMap {
private ActivityRepairId pk = new ActivityRepairId();
private Integer actRepCant;
#EmbeddedId
public ActivityRepairId getPk() {
return pk;
}
public void setPk(ActivityRepairId pk) {
this.pk = pk;
}
#Transient
public Activity getActivity() {
return getPk().getActivity();
}
public void setActivity(Activity activity) {
getPk().setActivity(activity);
}
#Transient
public Repair getRepair() {
return getPk().getRepair();
}
public void setRepair(Repair repair) {
getPk().setRepair(repair);
}
#Column(name="actRepCant")
public Integer getActRepCant() {
return actRepCant;
}
public void setActRepCant(Integer actRepCant) {
this.actRepCant = actRepCant;
}
public ActivityRepairMap (){
}
// hashCode and equals methods
}
ActivityRepairId
#Embeddable
public class ActivityRepairId implements Serializable{
private static final long serialVersionUID = -776429030880521951L;
private Activity activity;
private Repair repair;
#ManyToOne
public Activity getActivity() {
return activity;
}
public void setActivity(Activity activity) {
this.activity = activity;
}
#ManyToOne
public Repair getRepair() {
return repair;
}
public void setRepair(Repair repair) {
this.repair = repair;
}
// hashCode and equals method
}
My problem is that I can't query all the repairs used in a specific activity.
I've already checked in MySQL Workbench that the data stored in the DB is correct.
I would appreciate if anyone can explain me either using HQL or Criteria how can I achieve this.
Thanks a lot.
In SQL this should be:
SELECT
r.*
FROM
repair r
LEFT JOIN
activity_repair ar
ON
ar.repair_id = r.id
WHERE
ar.activity_id = ?
Now it's still possible that a single activity is connected with two repairs, and though you might get some repairs twice in the result list. You could simple use a SELECT DISTINCT r.* to work around this, or work with a subquery.
In JPQL the query should be bascially the same as the SQL from above.
SELECT
r
FROM
Repair r
WHERE
r.activityRepairMaps.pk.activity = ?
If you need a JOIN:
SELECT
r
FROM
Repair r
JOIN
ActivityRepairMap arm
WHERE
arm.pk.activity = ?
Maybe you need to use #MapsId within your ActivityRepairMaps class. (I haven't done JPQL for a while now)
As a far as I remember, you should NOT use Entities within your #EmbeddedId classes, but instead use the raw #Id type of the corresponding classes. Instead of Repair and Activity, you should use int and int.
I am trying to develop a web application and I was wondering if there is a way to utilize a foreign key without writing a lot of code.
My Trainees.java
#Entity
public class Trainees {
#Id
#GeneratedValue
private int traineesID;
private int groupsID;
#ManyToOne
#JoinColumn(name = "status_trainee")
private String status_TraineeID;
private int customersID;
private String name;
private String surname;
private String phoneDetails;
private String email;
public Trainees(){
}
public Trainees(String name, String surname, String phoneDetails, String email, int id, int groupsID, String status_TraineeID, int customersID) {
super();
this.name = name;
this.surname = surname;
this.email = email;
this.phoneDetails = phoneDetails;
this.groupsID = groupsID;
this.status_TraineeID = status_TraineeID;
this.customersID = customersID;
}
//getters and setters
#Override
public boolean equals(Object object) {
if (object instanceof Trainees){
Trainees contact = (Trainees) object;
return contact.traineesID == traineesID;
}
return false;
}
#Override
public int hashCode() {
return traineesID;
}
}
Status_Trainee.java
#Entity
public class Status_Trainee {
#Id
#GeneratedValue
private int status_traineeID;
private String value;
public Status_Trainee(){
}
public Status_Trainee(String value, int id) {
super();
this.value = value;
}
//getters and setters
#Override
public boolean equals(Object object) {
if (object instanceof Status_Trainee){
Status_Trainee value = (Status_Trainee) object;
return value.status_traineeID == status_traineeID;
}
return false;
}
#Override
public int hashCode() {
return status_traineeID;
}
}
Error: Caused by: org.hibernate.AnnotationException: #OneToOne or #ManyToOne on uaiContacts.model.Trainees.status_TraineeID references an unknown entity: String
So my aim is that using the Trainees table and class, I could retrieve the value of Status_Trainee table using the foreign key. For example: if foreign keys ID is 2, then it would retrieve a string from status_trainee table where primary key would match the foreign key ID.
I am using models, controlers, hibernate and angularjs to display to the view, I don't really want to pass the table through all this, I thought using something like ManyToOne or JoinColumns would retrieve the value?
Thanks for all the help!
You should add a reference to StatusTrainee in Trainee and annotate that with OneToMany, ManyToOne or OneToOne. Depending on which kind of relationship you will need a list of StatusTrainee or just a StatusTrainee.
Tip: dont use underscores in class names.
First of all, it is not recommended to use "_" in a class name when using hibernate. Hibernate uses underscores when accessing foreignKeys. So Lets Say you rename your class to: TraineeStatus and the id change it to traineeStatusId..
Secondly, You can use the Hibernate annotations for what you need. but first you need to know how the relation is:
#OneToMany : One Trainee can have lots of statuses
#ManytoOne : Many trainees can have the same status
#OneToOne : one Trainee Can only have one status and the other way around.
Try this:
#Entity
public class Trainees {
#Id
#GeneratedValue
private int traineesID;
private int groupsID;
#OneToOne
private TraineeStatus status;
private int customersID;
private String name;
private String surname;
private String phoneDetails;
private String email;
...
You can change the #OneToOne for the one you need..
Remember that hibernate will try to map this in your Trainees mysql table as status_traineeStatusId, so if you have this column (as an integer) at your trainess table you are done :)..
That is it..
Hope it helps
I've got two tables A and B with simple PK's.
#Entity
public class A {
#Id
public int idA;
}
#Entity
public class B {
#Id
public int idB;
}
I want to map a new association class AB that simply stores the relations between A and B, with composite PK idA+idB. AB doesn't have any extra columns, just the relation between idA and idB.
Is it possible to map AB using a single class? I want to avoid having to create a new ABId class just to use it as #IdClass or #EmbeddedId in AB, and I don't want to map this with a #ManyToMany association on A or B.
Why do you want to map such a join table? Just use a ManyToMany association between A and B. This join table will then be handled automatically when you'll add/remove a B to/from the list of Bs contained in A.
See http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#d0e11402
If you really want to do that, then just map the two IDs with the #Id notation. The primary class will be the entity class itself (which must be serializable), as explained in the hibernate reference documentation. Note that this is Hibernate-specific.
It would be nice if #JBNizet 's suggestion worked. Unfortunately, there's an old bug which makes it impossible to adopt it in the version I'm using (3.3.1-GA)
I've finally sorted this out by defining an inner static ID class and using it as #IdClass:
#Entity
#Table(name="TABLE_AB")
#IdClass(value=ClassAB.ClassABId.class)
public class ClassAB implements Serializable {
private String idA;
private String idB;
#Id
public String getIdA(){ return idA; }
public void setIdA(String idA){ this.idA = idA; }
#Id
public String getIdB(){ return idB; }
public void setIdB(String idB){ this.idB = idB; }
static class ClassABId implements Serializable {
private String idA;
private String idB;
#Column(name="ID_A")
public String getIdA(){ return idA; }
public void setIdA(String idA){ this.idA = idA; }
#Column(name="ID_B")
public String getIdB(){ return idB; }
public void setIdB(String idB){ this.idB = idB; }
// HashCode(), equals()
}
}
This way I don't have to define a new public class, and I don't have to modify the mappings file to include the ID class.
I've been having trouble with saving embedded collections. I've come up with this crazy solution because I wanted my lazily loaded models to sort based on fields in resources.
I have three tables:
assets (id)
assets_resources (asset_id,resource_id,primary_image)
resources (id,logical_name)
I have defined the tables with hibernate annotations like so:
Assets.java:
#Entity
#Table(name = "assets")
public class Asset implements java.io.Serializable {
#OneToMany
#Cascade(CascadeType.ALL)
#JoinTable(
name="assets_resources"
, joinColumns=#JoinColumn(name="asset_id")
, inverseJoinColumns=#JoinColumn(name="resource_id")
)
#MapKeyColumn(name="asset_id")
#OrderBy("logical_name")
private Map<AssetResource, Resource> resources;
public Map<AssetResource, Resource > getResources() {return resources;}
public void setResources(Map<AssetResource, Resource> resources) {this.resources = resources;}
}
assetResource.java
#Embeddable
public class AssetResource {
private Boolean primary_image;
public Boolean getPrimaryImage() {return primary_image;}
public void setPrimaryImage(Boolean primary_image) {this.primary_image = primary_image;}
private Long id;
public Long getId() {return id;}
}
resource.java
#Entity
#Table(name="resources")
public class Resource implements java.io.Serializable {
...
public String logical_name;
public String getLogicalName() {return logical_name;}
public void setLogicalName(String logical_name) { this.logical_name = logical_name;}
}
I can iterate though the lazily loaded maps in my controllers but I can't seem to save/update embedded fields. specifically, I can't update the primary_image field.
This link demonstrates what I was trying to do.
Are you able to save the attribute value in database. Because i think you won't be able to save the value as u have not mapped it with some column in the database. Try removind Emmbedded and then add the table and column attributes..