I am trying to map the same column to two diferent variables, like the following code:
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name="Class", insertable = false, updatable = false)
#Fetch(FetchMode.JOIN)
private ObjectClass classObject;
#Column(name="Class")
private int classID;
But when i try to get the classObject i get a null and the classID is with the right value. For some reason the classObject is not getting fetched....
Can you guys help???
Related
Am new to Hibernate and MySQL, i have two Table like OFFER_TABLE and OFFER_LIKES_DISLIKES
OFFER_TABLE Columns
OFR_ID(PK)
OFR_MSG
OFFER_LIKES_DISLIKES Columns
OFFER_LIKES_DISLIKES_ID
OFR_ID(FK)
LIKE
DISLIKE
I want to map OFFER_TABLE and OFFER_LIKES_DISLIKES, Access the OFFER_LIKES_DISLIKES data through OFFER_TABLE. Am using One to One Mapping but its not Working.
Hibernate Annotation Mapping Java Class
Offers.class
#Id
#GeneratedValue
#Column(name = "OFR_ID", length = 11, nullable = false)
private int offer_id;
#OneToOne
#JoinColumn(name="OFR_ID", unique = true)
#OneToOne(cascade = CascadeType.ALL)
private MessageLikeDislikesDAO likeDislikes;
LikeDislike.class
#GeneratedValue
#Column(name="LIKES_DISLIKES_ID", length = 11, nullable = false)
private int likes_dislikes_id;
#Expose
#Column(name="OFR_ID", length = 11, nullable = false)
private int offer_id;
When I get the Data of Offers, want Like and Dislike data associated with it. In LikeDislike table OFR_ID is UNIQUE. Am used One to One. But i didn't get the data of LikeDislike. Which one is best way to took that data. Help me to solve this issue.
There are many problems:
You're creating an association with a DAO instead of creating an association with an entity
You're storing the ID of the offer in the LikeDislike entity instead of storing an association with the Offer entity
You're saying that there is a join column named OFR_ID and referring to the LikeDislike entity in the OFFER table.
You disrespect Java naming conventions
You're setting two OneToOne annotations on the same field
The mapping should be:
Offer:
#Id
#GeneratedValue
#Column(name = "OFR_ID", length = 11, nullable = false)
private Integer offerId;
#OneToOne(mappedBy = "offer", cascade = CascadeType.ALL)
private LikeDislike likeDislike;
LikeDislike:
#GeneratedValue
#Column(name="LIKES_DISLIKES_ID", length = 11, nullable = false)
private Integer likeDislikeId;
#Expose
#OneToOne
#JoinColumn(name="OFR_ID", length = 11, nullable = false)
private Offer offer;
Relevant documentation
In our Java EE EJB application, we have the following JPA/Hibernate mapping of a class:
#Entity
#Table(name="T")
#TableGenerator( /* all annotation attributes */)
public class T {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#Column(name="SEQ_T", nullable = false)
private long seqT;
#OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true,
mappedBy = "t",
fetch = FetchType.LAZY
)
private List<W> wu;
}
and these are the classes which are in relation with it:
#Entity
#Table(name="W")
#TableGenerator( /* all annotation attributes */)
public class W {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#Column(name="SEQ_W", nullable = false)
private long seqW;
#Column(name="SEQ_T", nullable = false)
private long seqT;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SEQ_T", insertable = false, updatable = false)
private T t;
#OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true,
mappedBy = "w",
fetch = FetchType.LAZY
)
private List<WA> wua;
}
#Entity
#Table(name="WA")
#TableGenerator( /* all annotation attributes */)
public class WA {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#Column(name="SEQ_W_A", nullable = false)
private long seqWA;
#Column(name="SEQ_W", nullable = false)
private long seqW;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SEQ_W", insertable = false, updatable = false)
private W w;
}
Moreover, we have a scheduled job which is executed periodically by TimerService EJB.
First of all, this job must understand if there is something to execute so it performs a native sql query like the following to recover a list of pk from T table according several conditions:
List<Long> seqTs = (List<Long>)em.createNativeQuery("select SEQ_T from T").getResultList();
where em is an instance of EntityManager. The query is not obviously that simple but very complex as it derives from some JOIN and subqueries with other tables.
If the returned list is not empty, then the job can do its work and this JPQL is performed to load the entities it manipulates:
String queryJPQL = "select wu from W wu JOIN FECTCH wu.wua where wu.seqT in :seqTs";
List<Workup> wus = em.createQuery(queryJPQL, W.class)
.setParameter("seqTs", seqTs)
.getResultList();
This query is performed because even if we always need the data in #OneToMany relation, if we set that relation as EAGER then N+1 queries is performed. Instead, with JOIN FETCH a unique query is performed recovering a sort of view and then entities and relations are associated by Hibernate.
Well, the problem is that this exception is raised when .setParameter() is called:
Exception in thread "main" java.lang.IllegalArgumentException: Parameter value element [1] did not match expected type [java.lang.Long (n/a)]
Reading many posts here, and set a breakpoint in Eclipse, I discovered that not a List<Long> is returned from a native query but a List<BigInteger> (according to native type of PK in database), without any ClassCastException or similar. Why this?
So, I guess I should perform something like this before:
List<Long> seqTLong = new ArrayList<Long>();
for(BigInteger seqNative : seqTs)
seqTLong.add(seqNative.longValue());
and pass it to the query.
Anyway, is this the right solution? Is it safe? This because our application supports 3 DB and it is built accordingly in 3 JARs by ANT: Oracle, PostgreSQL and SQL Server.
Can I assume the value of PK is always BigInteger for each DB? In Oracle we use Number(19), in PostgreSQL we use BigInt...I don't remember about SQL Server.
This entities are then passed to DRools and when rules have been applied, this job uses EntityManager to persist data. That's why I need JPA entities to be loaded, otherwise I would get a
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist
or I would have to call .find() again for each fact modified by DRools and set its attributes by calling getters from the others. Which still causes N+1 queries.
A safer method would be to use Number instead of BigInteger
List<Long> seqTLong = new ArrayList<Long>();
for(Number seqNative : seqTs) {
seqTLong.add(seqNative.longValue());
}
I have an entity with collection of strings. I would like to add a constrains that will check if all items in the collection have size less then 255.
Let's say I have an entity Area with a collection of references. I would like to be sure that all references are shorter then 255 characters. Do you know how can I achieve it.
#Entity
#Table(name = "AREA")
public class Area Serializable {
private static final long serialVersionUID = -4756123949793458708L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Integer id;
#ElementCollection
#CollectionTable(name = "AREA_REFERENCES", joinColumns = #JoinColumn(name = "AREA_ID"))
#Column(name = "REFERENCE", nullable = false)
#Size(max = 255) // THIS ANNOTATION SEEMS TO NOT WORK
private Set<String> references = new HashSet<>();
....
Annotating like this
#Size(max = 255)
private Set<String> references;
means the Set<String> is allowed to contain a maximum of 255 strings.
Of course this is not what you want.
Instead, you want each string to have a maximum of 255 characters:
You can achieve it by annotating the type parameter within < > like this:
private Set<#Size(max = 255) String> references;
For that you will need quite new versions of Hibernate Validator (6.0.x)
and Bean Validation (2.0.1).
See also this answer for a similar problem.
According to how-to-limit-the-column-length-while-using-collection-of-primitive-type you could set the size constraint to the Column annotation.
For validation, you could add a like #Size(max=allowed_length) constraint from the Bean Validation API (JSR 303).
Hibernate uses Bean Validation constraints to generate an accurate database schema.
for example :
#Size.max leads to a varchar(max) definition for Strings and
#Min, #Max lead to column checks (like value <= max)
I have Language entity. And I want to realize ManyToMany association with the same table. translation_ways table have just two fields fromLangId int(3) and toLangId int(3).
#Entity(name = "Language")
#Table(name = "language")
public class Language implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "language_id")
private int id;
#NotBlank
#Column(name = "short_name", unique = true, length = 2, nullable = false)
private String shortName;
#NotBlank
#Column(name = "full_name", unique = true, nullable = false)
private String fullName;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "translation_ways",
joinColumns = #JoinColumn(name = "fromLangId"),
inverseJoinColumns = #JoinColumn(name = "toLangId"))
private Set<Language> toLangs;
//getters and setters here
//ovverrided equals() & hashCode()
}
What I want to do is to get the list of all Languages (with Set of the Languages entities joined by translation_ways table). The problem is that Criteria.list() returns list with duplicates. Amount of duplicates in the list is equal to how many times current id appears in the translation_ways.fromLangId column. In my case it is redundant information and I want to get list of unique Objects.
So the first question is if there is the some recommended or best of the best way to get this list without redundant elements? Convert returned ArrayList to LinkedHashSet? Or maybe I just did something wrong with my Criteria???
Also, have one more related question. If I'll call this query in the second time hibernate will take data from a cache, am I right?
I will appreciate any recommendations, ideas, links and help. Thanks everyone in advance.
my request:
Criteria c = this.template.getSessionFactory().getCurrentSession().createCriteria(Language.class);
c.setCacheable(true)
.setCacheMode(CacheMode.NORMAL)
.setCacheRegion("staticLangList");
List<Language> ls = c.list();
return ls;
P.S. Hibernate version is 5.0.1.Final.
use setResultTransformer in Criteria to avoid duplicates.
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
I have 3 elements like this:
public class ItemType {
#Id
private Long id = null;
...
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "itemTypeVO")
#MapKey(name = "company.id")
private Map<Long, ItemTypePurpose> purposeHash = null;
...
}
public class ItemTypePurpose {
#Id
private Long id = null;
...
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "idcompany")
private Company company = null;
...
}
public class Company {
#Id
private Long id = null;
...
}
My problem is, I want the ID of Company as key of my map inside ItemType .
I can compile and deploy the application without any errors. Can persist ItemType, and everything goes well to DB. But when I get it back, the Map key is "wrong", I don't know what information is being used, but for sure it's not the Company id. Perhaps the ItemTypePurpose's ID.
The Company is being loaded into Map correctly, just the map key is wrong. I've tryied to google, bu can't find anything. Does any way to JPA create my map with this "nested attribute"?
*Sorry about my english, feel free if you understand what I need and can do a better writing in english to edit my question.
This doesn't exactly solves the question, but solve my needs for now.
Since que ID of Company was in table of ItemTypePurpose, I could change the MapKey to:
public class ItemType {
#Id
private Long id = null;
...
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "itemTypeVO")
#MapKeyColumn(name = "idcompany", insertable = false, updatable = false)
private Map<Long, ItemTypePurpose> purposeHash = null;
...
}
Instead of #MapKey, I used #MapKeyColumn. The #MapKeyColumn(name = "idcore_company", insertable = false, updatable = false is to turn the "Key Information" ReadOnly and avoid mapping conflict, since the same column is used in ItemTypePurpose to map the Entity.
Not exactly an answer, but "worked around" to solve my needs. This solution does not cover if you want a field as Map Key other than the ID.
Late reply, but can be helpful to someone else.
#MapKeyColumn seems to be the official solution here. As per the documentation, it seems the annotation to be used depends on the key type of the Map, regardless of the mapped fields. In your case, the key type is a Long, hence below will apply:
https://docs.oracle.com/cd/E19226-01/820-7627/giqvn/index.html
Using Map Collections in Entities
Collections of entity elements and
relationships may be represented by java.util.Map collections. A Map
consists of a key and value.
If the key type of a Map is a Java programming language basic type,
use the javax.persistence.MapKeyColumn annotation to set the column
mapping for the key. By default, the name attribute of #MapKeyColumn
is of the form RELATIONSHIP FIELD/PROPERTY NAME_KEY. For example, if
the referencing relationship field name is image, the default name
attribute is IMAGE_KEY.
In summary:
For nested fields go for MapKeyColumn(name="myNestFiled_key"), then you will set the value manually in your code like:
ItemType.getPurposeHash().put(ItemTypePurpose.getCompany().getId(), ItemTypePurpose);