Im stuck with this problem. The database schema is provided by someone else so I cant simply change names. I tried add everywhere proper annotations, maybe I'm missing something (obvious)?
Here is my full mapping (quite many classess), I'll ommit getter/setters.
The problem is when hibernate is trying to get all List<ControlRuleAttrib> controlRuleAttribs
Controle Rule
#Entity
#Table(name = "CONTROL_RULE")
public class ControlRule implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "CONTROL_RULE_ID")
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#Cascade(CascadeType.ALL)
#JoinColumn(name = "CONTROL_RULE_TYPE_ID")
#ForeignKey(name = "CONTROL_RULE_TYPE_ID")
private ControlRuleType controlRuleType;
#Column(name = "JOB_NM")
private String jobname;
#Column(name = "LIBRARY_NM")
private String libraryname;
#Column(name = "TABLE_NM")
private String tablename;
#Column(name = "COLUMN_NM")
private String columnname;
#OneToMany(fetch = FetchType.LAZY)
#Cascade(CascadeType.ALL)
#JoinTable(name = "CONTROL_RULE_ATTRIB", joinColumns = {
#JoinColumn(name = "CONTROL_RULE_ID", nullable = false, updatable = false)
})
private List < ControlRuleAttrib > controlRuleAttribs;
}
ControlRuleAttrib
#Table(name = "CONTROL_RULE_ATTRIB")
#Entity
public class ControlRuleAttrib {
#EmbeddedId
private ControlRuleAttribPK controlRuleAttribPK;
#Column(name = "ATTRIBUTE_VALUE")
private String attributeValue;
}
ControleRuleAttribPK
Question here is, is it possible to somehow get Entity ControlRuleAttribType from ControlRuleAttrib? As you can see below ControlRuleAttribTypeId is the id of ControleRuleAttribType. I'd like to get whole object isteand of integer.
#Embeddable
public class ControlRuleAttribPK implements Serializable {
#Column(name = "CONTROL_RULE_ID")
private Long controlRuleId;
#Column(name = "ATTRIBUTE_SEQ_NUM")
private Integer attributeSeqNum;
#Column(name = "CONTROL_RULE_ATTRIB_TYPE_ID")
private Integer controlRuleAttribTypeId;
}
ControleRuleAttribType
#Entity
#Table(name = "CONTROL_RULE_ATTRIB_TYPE")
public class ControlRuleAttribType implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "CONTROL_RULE_ATTRIB_TYPE_ID")
private Integer id;
#Column(name = "CONTROL_RULE_ATTRIB_TYPE_NM")
private String typename;
#Column(name = "CONTROL_RULE_ATTRIB_TYPE_DESC")
private String typedesc;
#ManyToOne(fetch = FetchType.LAZY)
#Cascade(CascadeType.ALL)
#JoinColumn(name = "CONTROL_RULE_TYPE_ID")
#ForeignKey(name = "CONTROL_RULE_TYPE_ID")
private ControlRuleType controlruletype;
}
ControleRuleType
#Entity
#Table(name = "CONTROL_RULE_TYPE")
public class ControlRuleType implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "CONTROL_RULE_TYPE_ID")
private Integer id;
#Column(name = "CONTROL_RULE_TYPE_NM")
private String typename;
#Column(name = "CONTROL_RULE_TYPE_DESC")
private String typedesc;
}
EDIT
Here is stacktrace:
https://gist.github.com/a30dd9ce534d96bb9a97
As you'll find out, it fails here:
at
com.execon.controllers.main.MainPageController.getMainPage(MainPageController.java:33)
[classes:]
and this is it:
List<ControlRule> list = SessionFactoryUtils.openSession(
sessionFactory ).createQuery( "from ControlRule" ).list();
System.out.println( list );
every object which mapping I added, has toString() method declared like this:
#Override
public String toString()
{
String s = "ControlRule{";
s += "id=" + id.toString();
s += ", controlRuleType=" + controlRuleType;
s += ", jobname='" + jobname + '\'';
s += ", libraryname='" + libraryname + '\'';
s += ", tablename='" + tablename + '\'';
s += ", columnname='" + columnname + '\'';
s += ", controlRuleAttribs=" + controlRuleAttribs;
s += '}';
return s;
}
And hibernate request:
https://gist.github.com/c8584113522757a4e0d8/4f31dc03e7e842eef693fa7ba928e19d27b3ca26
Help please :)
EDIT 2
Well after reading #Jens answer, I did some changes in the code. First I did as you wrote and it gave error:
org.hibernate.AnnotationException: A Foreign key refering
com.execon.models.controlrules.ControlRuleAttrib from
com.execon.models.controlrules.ControlRule has the wrong number of
column. should be 3
I guess this is right, as I have composite primary key.
Then I tried it this way:
#OneToMany(fetch = FetchType.LAZY)
#Cascade(CascadeType.ALL)
#JoinTable(name = "CONTROL_RULE_ATTRIB",
joinColumns = {
#JoinColumn(name = "CONTROL_RULE_ID", nullable = false, updatable = false)
},
inverseJoinColumns = {
#JoinColumn(name = "CONTROL_RULE_ID", nullable = false, updatable = false),
#JoinColumn(name = "CONTROL_RULE_ATTRIB_TYPE_ID", nullable = false, updatable = false),
#JoinColumn(name = "ATTRIBUTE_SEQ_NUM", nullable = false, updatable = false)
})
private List<ControlRuleAttrib> controlRuleAttribs;
Quite close but it gives me the following exception:
Repeated column in mapping for collection..
So finally I removed
joinColumns =
{
#JoinColumn(name = "CONTROL_RULE_ID", nullable = false, updatable = false)
}
And everything compiled except that when I try to reach collection, Hibernate is doing following query:
https://gist.github.com/c88684392f0b7a62bea5
The last line, is controlrul0_.CONTROL_RULE_CONTROL_RULE_ID=? while it should be controlrul0_.CONTROL_RULE_ID=?.
Is there anyway I can make it work? :/
After struggling with this for last few hours I finally make it working within my project. The thing I did was this:
ControlRule
#OneToMany(fetch = FetchType.LAZY, mappedBy = "controlRuleAttribPK.controlRuleId")
#Cascade(CascadeType.ALL)
private List<ControlRuleAttrib> controlRuleAttribs;
Basically pointing that the collection should use controlRuleId from composite primary key. So far its working great!
I do not clearly understand which identifier is too long, but I can propose that you can try to change #Id annotated field types from Integer to Long. And it will be great to get some detailed info (stack trace etc.) about your problem.
The problem is the column
CONTROL_RULE_ATTRIB.controlRuleAttribs_CONTROL_RULE_ATTRIB_TYPE_ID
Which is so long it can't possibly exist in your database. I don't see in the question any hint how it is actually named, but I am assuming the proper name is
CONTROL_RULE_ATTRIB.CONTROL_RULE_ATTRIB_TYPE_ID
So the question is: Why is hibernate trying to access this column. The table it is in is a mapping table which is mapped in hibernate as:
#OneToMany(fetch = FetchType.LAZY)
#Cascade(CascadeType.ALL)
#JoinTable(name = "CONTROL_RULE_ATTRIB", joinColumns = {#JoinColumn(name = "CONTROL_RULE_ID", nullable = false, updatable = false)})
private List<ControlRuleAttrib> controlRuleAttribs;
If you look at the #JoinTable annotation you'll notice that it defines the table name as it is used and a join column. But a mapping table has two sets of join columns. The second on is not specified. Therefore the NamingStrategy you configured or if you didn't configured any the default is used. Just specify the other set of join columns using the attribute inverseJoinColumns and all should be fine.
The complete annotation should look like:
#JoinTable(name = "CONTROL_RULE_ATTRIB", joinColumns = {#JoinColumn(name = "CONTROL_RULE_ID", nullable = false, updatable = false)}, inverseJoinColumns = {#JoinColumn(name = "CONTROL_RULE_ATTRIB_TYPE_ID")})
Note: I have no idea if you need any of the nullable, updatable stuff on that column as well.
See also the documentation of the JoinTable annotation
Related
I have 2 models with one to one relationship
#Entity
#Table(name = "Form_Item_Production")
public class FormItemProduction {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "item_id", nullable = false)
private Long itemId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "shift_lookup_id", insertable = false, updatable = false)
private AppLookup appLookup;
getter and setter
}
The other one
#Entity
#Table(name = "App_Lookup")
public class AppLookup {
#Id
#GeneratedValue
#Column(name = "Lookup_Id", nullable = false)
private Long lookupId;
#Column(name = "Lookup_Name", length = 30, nullable = false)
private String lookupName;
getter and setter
}
When I try to persist to save the formitemproduction values
public boolean insertItem(List<FormItemProduction> f) {
for (FormItemProduction i : f) {
System.out.println("A" + i.getAppLookup().getLookupId()); // prints the correct id of applookup
i.setItemId(null);
entityManager.persist(i);
}
entityManager.flush();
return true;
}
I get this error
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.mamee.factory.security.entity.AppLookup
From my understanding this is unidirectional one to one mapping so I don't quite understand why I'm getting the error detached?
You have itemId which can't be null.
#Column(name = "item_id", nullable = false)
private Long itemId;
and you actually set itemId to null
i.setItemId(null);
So this line
entityManager.persist(i);
Is not able to persist your data.
Fixed by changing from:
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "shift_lookup_id", insertable = false, updatable = false)
private AppLookup appLookup;
to:
#OneToOne
#JoinColumn(name = "shift_lookup_id", insertable = true, updatable = true)
private AppLookup appLookup;
You have set cascade to ALL:
#OneToOne(cascade = CascadeType.ALL)
Which means you are cascading all operations down to the related field AppLookup.
You can set cascade to none, and you will no longer get your error, but no db operations will be executed for AppLookup field.
Let's say I have these Entities
Company,User,Project and Recommendation
But what I want to highlight is the Project and Recommendation table.
Below is the entity sample.
//Project entity
#Column(name = "id")
private String id;
#Column(name = "user_id")
private String userId;
#Column(name = "company_id", nullable = true)
private String companyId;
//Recommendation entity
#Column(name = "id")
private String id;
#Column(name = "user_id")
private String userId;
#Column(name = "company_id", nullable = true)
private String companyId;
#OneToMany(fetch = FetchType.LAZY)
#NotFound(action = NotFoundAction.IGNORE)
#JoinColumns({
#JoinColumn(name = "id", referencedColumnName = "user_id", nullable = true, insertable = false, updatable = false),
#JoinColumn(name = "id", referencedColumnName = "company_id", nullable = true, insertable = false, updatable = false)
})
private List<Project> projects;
Above tables are just illustration, sorry if that doesn't really make sense.
I want to join Project table inside Certification table.
They both are not directly related, so I need to join using these 2 columns, userId and companyId.
However, companyId is nullable. And whenever it is null, I still want to join the table only by userId.
What I want to achieve is probably along this line:
Select from Recommendation rec Join Project project
on rec.user_id = project.user_id and (rec.company_id = project.company_id OR rec.company_id is null)
Is it possible to use hibernate / JPA annotations to achieve this?
My project uses Hibernate 5 recently
I have following entities and need to retrieve a list of names of all stores that are in a specific group and have branches in a specific city. Majority of tutorials and articles that Ive found are related to creating this type of relationships but none of them is about retrieval!
I changed the criteria for many times but Hibernate shows different errors for each. The commented parts of the code are those that I tried and the respective thrown exception is also written in front of each.
Entities
#Entity
public class Store {
#Id
String id;
String name;
#JoinTable(name = "store_groups", joinColumns = { #JoinColumn(name = "id", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "code", nullable = false, updatable = false) })
private Set<Group> groups = new HashSet<Group>(0);
private Set<StoreAddress> storeAddresses = new HashSet<StoreAddress>(0);
....
}
#Entity
public class Group {
#Id
String code;
#Column(nullable = false, unique = true)
String name;
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "groups")
Set<Store> storees = new HashSet<Store>(0);
}
#Entity
#Table(name = "StoreAddresses")
#AssociationOverrides({
#AssociationOverride(name = "muJoinTable.store", joinColumns = #JoinColumn(name = "id", nullable = false)),
#AssociationOverride(name = "myJoinTable.city", joinColumns = #JoinColumn(name = "cityCode", nullable = false)) })
public class StoreAddress {
#EmbeddedId
private StoreCitysId myJoinTable = new StoreCitysId();
...
}
#Embeddable
public class StoreCitysId {
#ManyToOne
private Store store;
#ManyToOne
private City city;
}
#Entity
public class City {
#Id
short code;
#Column(nullable = false)
String name;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "myJoinTable.city")
private Set<StoreAddress> storeAddresses = new HashSet<StoreAddress>(
0);
}
Criteria
List<String> storees = (List<String>) sessionFactory
.getCurrentSession()
.createCriteria(Store.class)
.setProjection(
Projections.property("name").as(
"storeName"))
.createAlias("groups", "group")
.createAlias("storeAddresses", "address")
// .createAlias("address.myJoinTable.city", "city")
// .createAlias("address.myJoinTable", "myJoinTable")
// .createAlias("myJoinTable.city", "city") Error: Criteria objects cannot be created directly on components
.setFetchMode("group", FetchMode.JOIN)
.add(Restrictions.ilike("group.code", store))
.add(Restrictions.eq("address.myJoinTable.cityCode",
1)).list(); //city.code -> Error: could not resolve property: cityCode of:com.example.entity.StoreAddress address.myJoinTable.cityCode could not resolve property: myJoinTable.cityCode of:com.example.entity.StoreAddress
Your criterion Restrictions.eq("address.myJoinTable.cityCode", 1) doesn't reference a property but the name of the column. You could instead use address.myJoinTable.city and set the value to session.load(City.class, 1) making Restrictions.eq("address.myJoinTable.city", session.load(City.class, 1))
And this:
.createAlias("address.myJoinTable", "myJoinTable")
.createAlias("myJoinTable.city", "city")
Should be:
.createAlias("address.myJoinTable.city", "city")
I am having trouble mapping my database domain model to the program entities in one case where the entity is essentially a join table (a period) which combines two other entities (a timeslot and a day). Another entity (a lesson) then has a reference to this period entity, determining when it occurs.
When I try to save a lesson with a new period using saveOrUpdate(lesson) hibernate throws an IdentifierGenerationException
org.hibernate.id.IdentifierGenerationException: null id generated for:class com.trials.domain.Period
The database looks like below (not the real database, just the key tables and columns)
In the java hibernate model, I have used an embedded id for the primary key of the period class and the lesson class then has a reference to a period.
Period.java
#Entity
#Table(name = "period")
public class Period{
#EmbeddedId
private PeriodId periodId;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "day_idday", nullable = false, insertable = false, updatable = false)
private Day day;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "timeslot_idtimeslot", nullable = false, insertable = false, updatable = false)
private Timeslot timeslot;
//constructors, getters, setters, hashcode, and equals
}
And the embedded id just has the primary key columns:
PeriodId.java
#Embeddable
public class PeriodId implements Serializable {
#Column(name = "timeslot_idtimeslot")
private int timeslotId;
#Column(name = "day_idday")
private int dayId;
//constructors, getters, setters, hashcode, and equals
}
Then there is the lesson class that uses the period defined as:
Lesson.java
#Entity
#Table(name = "lesson")
public class Lesson {
#Id
#Column(name = "idlesson")
private int lessonId;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumns({#JoinColumn(name = "period_timeslot_idtimeslot", nullable = false, updatable = false), #JoinColumn(name = "period_day_idday", nullable = false, updatable = false)})
private Period period;
//constructors, getters, setters, hashcode, and equals
}
The Timeslot and Day entity classes are both very basic pojos, and their ids use GenerationType.AUTO. So my problems are:
What causes this IdentifierGenerationException
How to avoid it while keeping the same database model
Thanks in advance
Put those guys
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "day_idday", nullable = false, insertable = false, updatable = false)
private Day day;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "timeslot_idtimeslot", nullable = false, insertable = false, updatable = false)
private Timeslot timeslot;
inside the PeriodId class and throw away those ints. I have done a mapping similar to yours this way and it works.
I was able to create the following mapping for my case (scala code) and could totally throw away the #Embeddable class:
#Entity
#Table(name = "payment_order_item", schema = "pg")
#IdClass(classOf[PaymentOrderItem])
final class PaymentOrderItem extends Serializable{
#Id
#ManyToOne
#JoinColumn(name = "order_item_id", referencedColumnName = "id")
var orderItem: OrderItem = _
#Id
#ManyToOne
#JoinColumn(name = "payment_id", referencedColumnName = "id")
var payment: Payment = _
}
So the following should work for you then
#Entity
#Table(name = "period")
#IdClass(Period.class)
public class Period extends Serializable{
#Id
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "day_idday", referencedColumnName = "id", nullable = false)
private Day day;
#Id
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "timeslot_idtimeslot", referencedColumnName = "id", nullable = false)
private Timeslot timeslot;
//constructors, getters, setters, hashcode, and equals
}
On a first glance,
You're missing the generated value annotation in the embedded id class.
#Embeddable
public class PeriodId implements Serializable {
#GeneratedValue
#Column(name = "timeslot_idtimeslot")
private int timeslotId;
#GeneratedValue
#Column(name = "day_idday")
private int dayId;
//constructors, getters, setters, hashcode, and equals
}
I have two tables in the clients mssql database. The first is a job table - so I created an Job entity which contains the load type and load weight and all that stuff - works fine.
My problem now is that there is a second table that includes informations about the load and unload point. The second table, I call it JEP, has a primary key consisting of several items: the type (load or unload), the zip code and the customer number.
I created an entity JobEndPoint and NetBeans also created an object representing the primary key JobEndPointPK containing all that fields.
I want to add two JobEndPoint (loadPoint and unloadPoint) to my Job entity. My problem is now: how do I annotate that in Hibernate? In my opinion it is an #OneToOne relation ship. It would be perfect if I could specify a SELECT statement like SELECT * FROM JEP WHERE type="load" AND customer_nr="123" AND zip_code="123 ...". Is that possible with Hibernate?
Thanks for your help!
Regeards,
Marco
Here are the Entities:
#Entity
#Table(name = "Auftragsdaten", catalog = "...", schema = "dbo")
public class Job implements Comparable<Object>, Serializable {
private static final long serialVersionUID = 4285871251915951149L;
#Id
#Basic(optional = false)
#Column(name = "`id`", nullable = false)
int id;
#Column(name = "`AufNr`", nullable=false)
int jobId;
#Transient
List<Integer> jobsAdded;
#Column(name = "`Beladedatum`", nullable=false)
#Temporal(TemporalType.DATE)
Date loadDate;
#Column(name = "`Beladezeit`")
#Temporal(TemporalType.TIME)
Date loadTimeFrom;
#Transient
Date loadTimeTo;
#Column(name = "`Entladedatum`", nullable=false)
#Temporal(TemporalType.DATE)
Date unloadDate;
#Column(name = "`Entladezeit Beginn`")
#Temporal(TemporalType.TIME)
Date unloadTimeFrom;
#Column(name = "`Entladezeit Ende`")
#Temporal(TemporalType.TIME)
Date unloadTimeTo;
#Transient
List<JobEndPoint> froms;
#OneToOne
#JoinColumns ({
#JoinColumn(name="`Beladetyp`", referencedColumnName = "`Ladetyp`", insertable = false, updatable = false),
#JoinColumn(name="`AbsNr`", referencedColumnName = "`KundenNr`", insertable = false, updatable = false),
#JoinColumn(name="`Verkehrsart`", referencedColumnName = "`VerkArt`", insertable = false, updatable = false),
#JoinColumn(name="`von LKZ`", referencedColumnName = "`LKZ`", insertable = false, updatable = false),
#JoinColumn(name="`von PLZ`", referencedColumnName = "`PLZ`", insertable = false, updatable = false)
})
JobEndPoint fromPoint;
#Transient
JobEndPoint toPoint;
#Column(name = "`Verkehrsart`", length = 10, nullable=false)
#Enumerated
JobType type;
#Column(name = "`Anzahl Paletten CCG1`")
int numberCCG1;
#Column(name = "`Anzahl Paletten CCG2`")
int numberCCG2;
#Transient
int numberFullContainer;
#Transient
int numberEmptyContainer;
#Column(name = "`Anzahl Container`")
int numberContainer;
#Column(name = "`Anz Stellplätze`")
int numberUnits;
#Column(name = "`Bruttogewicht`", nullable=false)
int loadWeight;
#ManyToOne
#JoinColumn(name="`Kühlkennzeichen`")
CoolingCode coolingCode;
}
#Entity
#Table(name = "BES", catalog = "...", schema = "dbo")
public class JobEndPoint implements Serializable {
private static final long serialVersionUID = 1017986852824783744L;
#Id
protected JobEndPointPK jobEndPointPK;
(...)
}
#Embeddable
public class JobEndPointPK implements Serializable {
#Basic(optional = false)
#Column(name = "`Ladetyp`", nullable = false, length = 50)
#Enumerated
EndPointType type;
#Basic(optional = false)
#Column(name = "`KundenNr`", nullable = false)
int customerId;
#Basic(optional = false)
#Column(name = "`VerkArt`", nullable = false, length = 10)
#Enumerated
JobType jobType;
#Basic(optional = false)
#Column(name = "`LKZ`", nullable = false, length = 3)
String countryCode;
#Basic(optional = false)
#Column(name = "`PLZ`", nullable = false, length = 7)
String zipCode;
}
In general, I would recommend using a generated internal primary key instead of the composite key. However, if you need to stick with your composite key, here are some ideas that hopefully help.
I understand that JobEndPointPK is implemented as an identifier component (see the Hibernate Reference, chapter 8.4). Note: it is critical that it implements the equals and hashCode` methods correctly, as Hibernate relies on these.
Updated: Provided that your JobEndPoint and JobEndPointPK looks something like this:
#Embeddable
class JobEndPointPK {
#Column(name = "type", nullable = false)
#Enumerated
EndPointType type;
#Column(name = "zipCode", nullable = false)
String zipCode;
#Column(name = "customerNumber", nullable = false)
int customerId;
// equals, hasCode, getters, setters etc.
}
#Entity
class JobEndPoint {
#Id
private JobEndPointPK key;
// getters, setters etc.
}
The mapping annotation would be something like:
#Entity
class Job {
#OneToOne
#JoinColumns ({
#JoinColumn(name="loadPointType", referencedColumnName = "type"),
#JoinColumn(name="loadPointZip", referencedColumnName = "zipCode"),
#JoinColumn(name="loadPointCust", referencedColumnName = "customerNumber")
})
private JobEndPoint loadPoint;
// similarly for unloadPoint
// other properties
}
The example is adapted from here.
I am not sure how to deal with JobEndPointPK.type though, as for loadPoint it is obviously Load and for unloadPoint, Unload, so you most probably don't want to store it separately in the DB. My gues is that you can specify the value with the #Formula annotation, but I haven't seen any concrete example for this.
Note that all this code is purely experimental, I haven't tested it.
There are other variations on the theme. For more details, see the section "Composite keys with annotations" in Chapter 8 of Java Persistence with Hibernate.