How to add constraint to collection items - java

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)

Related

What difference does it make to put an annotation #Lob or not?

There is a request table in my database.
Here is its structure
Usually I created the entity with my hands, but this time I decided to generate it from the database. Here's what I got
#Entity
#Table(name = "request")
public class Request
{
#Id
#Column(name = "id", nullable = false)
private Integer id;
#Lob
#Column(name = "body")
private String body;
#Column(name = "description", length = 10000)
private String description;
#Lob
#Column(name = "headers")
private String headers;
#Column(name = "http_method", nullable = false, length = 20)
private String httpMethod;
#Column(name = "name", nullable = false, length = 100)
private String name;
#Lob
#Column(name = "path_variables")
private String pathVariables;
#Column(name = "port")
private Integer port;
#Lob
#Column(name = "query_params")
private String queryParams;
#Lob
#Column(name = "url", nullable = false)
private String url;
I noticed that a strange annotation #Lob appeared.
I've never seen her before. I decided to Google what it means and why to put it.
I found a lot of answers and they all said that this annotation is needed so that Hibernate understands that there may be a big object here.
But it seems to me that this annotation does nothing. After all, regardless of whether it is worth it or not, everything works the same?
What is it for?
From the looks of it, your entity generation tool just marked with #Lob all the columns that don't have the length specified - most likely just to make sure that whatever data you put into them it will fit.
(Say, in Oracle maximum BLOB/CLOB size is (4 GB - 1) * DB_BLOCK_SIZE initialization parameter (8 TB to 128 TB))
As for the #Lob itself, here's what javadoc says:
Specifies that a persistent property or field should be persisted as a large object to a database-supported large object type.
Portable applications should use the Lob annotation when mapping to a database Lob type. The Lob annotation may be used in conjunction with the Basic annotation or the ElementCollection annotation when the element collection value is of basic type. A Lob may be either a binary or character type.
The Lob type is inferred from the type of the persistent field or property, and except for string and character-based types defaults to Blob.
The common usecase for binary lobs (BLOBs) is storing some binary file content in the database, say an image, and for the character lobs (CLOBs) - large texts documents.

One to One Mapping in Hibernate Unidirectional with MySQL DB?

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

Is there any way to get unique elements in list when realizing ManyToMany association?

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

JPA MapKey with Nested Attributes

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

How to exclude an entity field when doing an update with JPA

Is there a way to make a field non-persistent at update operation but persistent at create operation with JPA - Hibernate 4?
I tried it in this way
#Transient
#Id
#Column(name = "USER_NAME", nullable = false, length = 75)
private String userName;
but with #Transient annotation the field will be transient across all CRUD operations and I want a way to specify that only on this operation is persistent (create).
Is there a way to do this?
Thanks!
You need to set updatable attribute of the #Column annotation to false:
#Column(name = "USER_NAME", nullable = false, length = 75, updatable= false)
private String userName;
The updatable attribute instruct Hibernate to omit this column from the generated UPDATE SQL statement.
I removed the #Transient and the #Id annotations.
If this column is your PK (mapped to the entity identifier), then you can only set it during INSERT, since Hibernate doesn't allow you to update an entity identifier (the updatable attribute being redundant in this case).

Categories

Resources