Hibernate criteria cannot retrieve values of a join - java

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")

Related

I need to get all distinct columns from the same table by the same code utilizing Hibernate

I have a table with n x n relationship. That means i have a code that is repeated with only a "brand" column being different between them. The code is not the ID.
I need to have one distinct class that contains all repeatable values and with a list that has all the unique brand column values.I cannot show most of the code samples because of my company security policies. But the entity below is a mock of what i'm seeking.
`
#Entity
#Table(name = "Table")
public class Teste {
#Column(name = "CODE", insertable = false, updatable = false)
private String code;
#Column(name = "NAME")
private String name;
#Column(name = "BRAND")
private String brand;
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(name = "BRAND", joinColumns = { #JoinColumn(name = "CODE"), #JoinColumn(name = "BRAND")})
private Set<Model> brands = new HashSet<>();
#Column(name = "UPDATE_DATE")
private Date update_date;
#Column(name = "EDITOR")
private String editor;
#Id
#Column(name = "ID")
private int id;
}
`

Hibernate filter apply every time entity is loaded

I am trying to write a multilanguage software. Using filters in hibernate, I want that every time an entity is accessed, only translation with the specific language being load.
#Entity
#Table(name = "province")
#FilterDef(name = "findByLanguage", parameters = {#ParamDef(name = "language", type = "string")})
public class Province {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name = "country_id", nullable = false)
private Country country;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "province_id")
#Filter(name = "findByLanguage", condition = "language = :language")
private Set<ProvinceTranslation> translations;
}
This works as I expected for province, But Country has also a list of translations, and I want that CountryTranslation list is also contains only specified language when I load a province. But this code does not work:
#Entity
#Table(name = "country")
#FilterDef(name = "findByLanguage", parameters = {#ParamDef(name = "language", type = "string")})
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "country_id")
private List<Province> provinces;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "country_id")
#Filter(name = "findByLanguage", condition = "language = :language")
private Set<CountryTranslation> translations;
}
So if I load Country directly everything is ok, But if I load Province and access Country inside it, loading Country is different and #Filter is being ignored. How can I achieve this?

Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements

I have one lawyer table which is having id(int) as a primary key and Country table having country_code(String ) as a primary key. I want to create third table using #JoinTable annotation in hibernate with two foreign key in it. But when I run it following error is coming. Not sure how to map one string and one int as foreign keys in third table.
Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements: com.test.common.entities.Country.lawyer
This is my code
#Entity
#Table(name = "lawyer")
public class Lawyer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "lawyer_batch_no")
private int lawyerbatchNo;
#ManyToOne(targetEntity = Country.class, cascade = { CascadeType.ALL })
#JoinTable(name = "lawyer_cscd", joinColumns = {
#JoinColumn(name = "lawyer_batch_no", referencedColumnName = "lawyer_batch_no") }, inverseJoinColumns = {
#JoinColumn(name = "country_code", referencedColumnName = "country_code") })
private Country country;
getter setter...
}
#Entity
#Table(name = "country")
public class Country {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "country_code")
protected String country_code;
#Column(name = "abbreviation")
protected String abbreviation;
#Column(name = "name", nullable = false)
protected String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "country")
protected Set<State> state = new HashSet<State>();
#OneToMany(targetEntity = Lawyer.class, cascade = { CascadeType.ALL }, orphanRemoval = true)
#JoinTable(name = "lawyer_cscd", joinColumns = {
#JoinColumn(name = "country_code", referencedColumnName = "country_code") }, inverseJoinColumns = {
#JoinColumn(name = "lawyer_batch_no", referencedColumnName = "lawyer_batch_no") })
private Lawyer lawyer;
getter setter....
}
The error indicates that private Lawyer lawyer needs to be a collection as it's a #OneToMany relationship. In the Country class, the last relationship should be
#OneToMany(targetEntity = Lawyer.class, cascade = { CascadeType.ALL }, orphanRemoval = true)
#JoinTable(name = "lawyer_cscd", joinColumns = {
#JoinColumn(name = "country_code", referencedColumnName = "country_code") }, inverseJoinColumns = {
#JoinColumn(name = "lawyer_batch_no", referencedColumnName = "lawyer_batch_no") })
private Set<Lawyer> lawyer;
// or a Collection/List/etc.

Hibernate many-to-many mapping referencing partial composite key

My problem is like this one: https://forum.hibernate.org/viewtopic.php?f=1&t=1002125
I have the following tables in my schema:
a table A with a composite key (attr1, attr2);
a table B with a pk (attr3);
and a table A_B which is a relationship table between A and B with a composite key (fk_attr1, fk_attr3), where fk_attr1 and fk_attr3 references the fields attr1 and attr2, respectively
The attr2 is not used in the relationship.
I generated the mapping java classes with hibernate plugin, and the generated code looks like this:
class A
private Set<B> bs = new HashSet<B>(0);
private AId id;
#EmbeddedId
#AttributeOverrides({ #AttributeOverride(name = "attr1", column = #Column(name = "attr1", nullable = false)),
#AttributeOverride(name = "attr2", column = #Column(name = "attr2", nullable = false)) })
public AId getId() {
return this.id;
}
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "A_B", catalog = "my_schema", joinColumns = { #JoinColumn(name = "fk_attr1", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "fk_attr3", nullable = false, updatable = false) })
public Set<B> getBs() {
return this.bs;
}
class B
private Set<A> as = new HashSet<A>(0);
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "A_B", catalog = "my_schema", joinColumns = { #JoinColumn(name = "fk_attr3", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "fk_attr1", nullable = false, updatable = false) })
public Set<A> getAs() {
return this.as;
}
class AId (the id for entity A)
private String attr1;
private Long attr2;
#Column(name = "attr1", nullable = false)
public String getAttr1() {
return this.attr1;
}
#Column(name = "attr2", nullable = false)
public Long getAttr2() {
return this.attr2;
}
But it always generates this exception:
org.hibernate.AnnotationException: A Foreign key refering A from B has the wrong number of column. should be 2
What is the right way to accomplish this relationship with Hibernate?

hibernate oracle identifier is too long ORA-00972

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

Categories