Hibernate allocationSize ignores "allocationSize" - java

How to put in order hibernate and database sequence generation?
My entity:
package kz.open.sankaz.model;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.security.core.GrantedAuthority;
import javax.persistence.*;
#Entity
#Table(name = "SEC_ROLE")
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class SecRole extends AbstractEntity implements GrantedAuthority {
#Id
#GeneratedValue(generator = "SEC_ROLE_SEQ", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(allocationSize = 1, sequenceName = "SEC_ROLE_ID_SEQ", name = "SEC_ROLE_ID")
private Long id;
#Column(name = "NAME", nullable = false, unique = true)
private String name;
#Override
public String getAuthority() {
return getName();
}
}
I wrote that "allocationSize" is 1. But Hibernate generates wrong query:
Hibernate: create sequence public.sec_role_seq start 1 increment 50
It makes a problem not only while you are inserting a new data, it also makes problem when you are running database migration queries. For example, I wrote the next line:
create sequence public.sec_role_seq start 1 increment 1;
and Hibernate conflicts with it:
The increment size of the [SEC_ROLE_SEQ] sequence is set to [50] in the entity mapping while the associated database sequence increment size is [1]
How to solve it? Please, help!

I solved it changing generator in the following way:
#Entity
#Table(name = "SEC_ROLE")
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class SecRole extends AbstractEntity implements GrantedAuthority {
#Id
#GeneratedValue(generator = "SEC_ROLE_SEQ", strategy = GenerationType.SEQUENCE)
#GenericGenerator(
name = "SEC_ROLE_SEQ",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
#Parameter(name = "sequence_name", value = "SEC_ROLE_SEQ"),
#Parameter(name = "initial_value", value = "1"),
#Parameter(name = "increment_size", value = "1")
}
)
private Long id;
#Column(name = "NAME", nullable = false, unique = true)
private String name;
#Override
public String getAuthority() {
return getName();
}
}

Related

Insert parent and Child in Springboot through Postman

I want to save a record and its child list with spring boot through postman in a One-to-Many relationship. The child list is saved but they don't take the Id of the parent automatically. How can i force the child to automatically take the id of the parent in Post Request In Postman?
Parent Class
package fdsa.edu.pnu.Model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Data
#Table(name = "Concours")
public class Concours implements Serializable {
#Column(name = "ID", nullable = false, length = 10)
#Id
#GeneratedValue(generator = "PNU_CONCOURS_ID_GENERATOR")
#org.hibernate.annotations.GenericGenerator(name = "PNU_CONCOURS_ID_GENERATOR", strategy = "native")
private Integer id;
#Column(name = "DateDebut", nullable = true)
#Temporal(TemporalType.DATE)
private java.util.Date DateDebut;
#Column(name = "DateFin", nullable = true)
#Temporal(TemporalType.DATE)
private java.util.Date DateFin;
#Column(name = "Description", nullable = true, length = 255)
private String description;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "concours",
cascade = CascadeType.ALL,targetEntity = fdsa.edu.pnu.Model.PlannificationConcours.class)
private List<PlannificationConcours> plannificationConcourses;
}
Child Class
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.io.Serializable;
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "PlannificationConcours")
public class PlannificationConcours implements Serializable {
#Column(name = "ID", nullable = false, length = 10)
#Id
#GeneratedValue(generator = "PNU_PLANNIFICATIONCONCOURS_ID_GENERATOR")
#org.hibernate.annotations.GenericGenerator(name = "PNU_PLANNIFICATIONCONCOURS_ID_GENERATOR", strategy = "native")
private int id;
#ManyToOne(targetEntity = fdsa.edu.pnu.Model.Concours.class, fetch = FetchType.LAZY)
#JoinColumns(value = {#JoinColumn(name = "ConcoursID", referencedColumnName = "ID")}, foreignKey = #ForeignKey(name = "ConcoursPlannificationConCours"))
private Concours concours;
#Column(name = "`Date`", nullable = true)
#Temporal(TemporalType.DATE)
private java.util.Date Date;
#Column(name = "Quotation", nullable = true, length = 10)
private double quotation;
#Column(name = "NoteDePassage", nullable = true, length = 10)
private double noteDePassage;
}```
Screen Shote where the Id of the parent is null
[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/LlnhP.png
There are 2 ways to reach it. And this is the minimal setting to do it:
Unidirectional
#Entity
#NoArgsConstructor
#Getter
#Setter
public class Concours {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "concours_id") // this line will play the role that passes the parent's id to its children
private List<PlannificationConcours> plannificationConcourses = new ArrayList<>();
}
#Entity
#NoArgsConstructor
#Getter
#Setter
public class PlannificationConcours {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
#Test
void saveConcours() {
Concours concours = new Concours();
concours.setPlannificationConcourses(List.of(new PlannificationConcours(), new PlannificationConcours()));
this.concoursRepository.save(concours);
}
This's all you need to propagate the parent's id. But the child won't have the reference to its parent by this way.
Bidirectional
#Entity
#NoArgsConstructor
#Getter
public class Concours {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToMany(mappedBy = "concours" ,cascade = CascadeType.ALL) // mappedBy will create a bidirectional relation for us
private List<PlannificationConcours> plannificationConcourses = new ArrayList<>();
public void addPlannificationConcours(PlannificationConcours child) {
child.setConcours(this); // and don't forget to set the parent instance to the child
this.plannificationConcourses.add(child);
}
}
#Entity
#NoArgsConstructor
#Getter
#Setter
public class PlannificationConcours {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
private Concours concours;
}
#Test
void saveConcours() {
Concours concours = new Concours();
concours.addPlannificationConcours(new PlannificationConcours());
concours.addPlannificationConcours(new PlannificationConcours());
this.concoursRepository.save(concours);
}

Spring Boot: Set hibernate sequence globally

Currently I define the tables the following way:
The example is in Kotlin, but you can answer in Java if you want.
#Entity
data class Task(#Id #GeneratedValue(strategy = GenerationType.SEQUENCE)
var id: Int = 0,
#ManyToOne(optional = false) #OnDelete(action = OnDeleteAction.CASCADE)
var exercise: Exercise = Exercise(),
#Column(nullable = false)
var name: String = "")
#Entity
data class Exercise(#Id #GeneratedValue(strategy = GenerationType.SEQUENCE)
var id: Int = 0,
#Column(nullable = false)
var count: Int = 0)
Using this example all tables are using the same sequence: hibernate_sequence.
If I want to configure it e.g. setting a custom allocationSize, then I must define it in every table, am I right?
#SequenceGenerator(name = "task_seq", sequenceName = "task_seq", allocationSize = 100)
Is there a Bean or anything else? Because I like the idea of using the same sequence for all tables.
You can have an abstract base class with Id like :
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
#MappedSuperclass
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
and every entity will extend this.

java.lang.IllegalStateException: Multiple representations of the same entity [] are being merged. Detached: []; Detached: []

I have three entities EntityA, EntityB and EntityC as follows:
EntityA:
import lombok.*;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table(name = "Entity_A")
#Getter
#Setter
#Builder
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode(of = "locationA")
#ToString(of = "locationA")
public class EntityA {
#Id
#Column(name = "Name_A", length = 10)
private String nameA;
#Column(name = "Loc_A", length = 10)
private String locationA;
#ManyToMany(cascade = { CascadeType.MERGE })
#JoinTable(
name = "En_A_On_B",
joinColumns = { #JoinColumn(name = "Name_A") },
inverseJoinColumns = { #JoinColumn(name = "B_id") }
)
private Set<EntityB> bs;
}
EntityB:
import lombok.*;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table(name = "Entity_B")
#Setter
#Getter
#Builder
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode(of = "locationB")
#ToString(of = "locationB")
public class EntityB {
#Id
#GeneratedValue
#Column(name = "B_id")
private int id;
#Column(name = "Loc_B", length = 10)
private String locationB;
#ManyToMany(cascade = { CascadeType.MERGE })
#JoinTable(
name = "En_C_on_B",
joinColumns = { #JoinColumn(name = "B_id") },
inverseJoinColumns = { #JoinColumn(name = "C") }
)
private Set<EntityC> cs;
}
EntityC:
import lombok.*;
import javax.persistence.*;
import java.util.Set;
#Entity
#Table(name = "Entity_C")
#Getter
#Setter
#Builder
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode(of = "c")
#ToString(of = "c")
public class EntityC {
#Id
#Column(name = "C", length = 20)
private String c;
}
SERVICE CLASS TO SAVE:
#Service
#Slf4j
public class ServiceClass {
#Autowired
private EntityARepository entityARepository;
private Set<EntityC> cs1 = new HashSet<>(asList(
EntityC.builder().c("100").build(),
EntityC.builder().c("10").build()
));
private Set<EntityC> cs2 = new HashSet<>(asList(
EntityC.builder().c("100").build(),
EntityC.builder().c("200").build()
));
//METHOD TO SAVE
public void save() {
Map<String, Set<EntityC>> map = new HashMap<>();
map.put("B1", cs1);
map.put("B2", cs2);
List<String> bs = asList("B1", "B2");
EntityA aa = EntityA.builder().nameA("abcd").locationA("mon").build();
EntityA ab = EntityA.builder().nameA("abcde").locationA("money").build();
bs.forEach(b -> {
EntityB entityB = EntityB.builder().locationB("100xxx").build()
entityB.getCs().addAll(map.get(b));
aa.getBs().add(entityB);
ab.getBs().add(entityB);
});
entityARepository.save(aa);
entityARepository.save(ab);
}
}
Execution of above code throws following exception
Caused by: java.lang.IllegalStateException: Multiple representations of the same entity [com.xxx.xxx.xxx.xxx.EntityC#100] are being merged. Detached: [(c=100)]; Detached: [(c=100)]
Note: I have explored on the internet but none of them matcches with my scenario
Any idea how can I rectify the issue
The problem is right here:
private Set<EntityC> cs1 = new HashSet<>(asList(
EntityC.builder().c("100").build(), //this entity instance has the same identifier...
EntityC.builder().c("10").build()
));
private Set<EntityC> cs2 = new HashSet<>(asList(
EntityC.builder().c("100").build(), //...as this one
EntityC.builder().c("200").build()
));
You are trying to persist two versions of the same entity, in a single unit of work. Imagine you put:
EntityC.builder().c("100").name("A name").build()
in cs1 and:
EntityC.builder().c("100").name("Another name").build()
in cs2 instead. Since both entities have the same id (c="100"), how is Hibernate supposed to know which version 'wins'?
Try putting the same instance of EntityC in both sets and the problem should go away.

jsp not showing spring validator errors

I am creating a project using spring MVC.
I am validating fields using jsr303.
It is working fine It showing errors of fields in console but not in jsp page
Can any one let me know what wrong I am doing here ?
My controller method is
#RequestMapping(value="/addCampaign", method = RequestMethod.POST)
public String processForm(#ModelAttribute(value="Campaign") #Valid CampaignEntity campaignObj,BindingResult result, ModelMap model, Principal principal) {
validator.validate(campaignObj, result);
if(result.hasErrors()){
System.out.println(result.getErrorCount());
System.out.println(result.toString());
CampaignEntity campaignBean = new CampaignEntity();
Map<String,String> agencies = new LinkedHashMap<String,String>();
agencies.put("1", "United Stated");
agencies.put("2", "China");
agencies.put("3", "Singapore");
agencies.put("4", "Malaysia");
model.addAttribute("agencies", agencies);
model.addAttribute("publishers", agencies);
model.addAttribute("Campaign", campaignBean);
return "addCampaign";
}else{
return campaign(model, principal);
}
}
In jsp I am showing error using tag
<form:errors path="*" cssClass="error" />
my entity class is
package com.nativeunlock.dto;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.*;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotEmpty;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
#SuppressWarnings("serial")
#NamedQueries({
#NamedQuery(
name = CampaignEntity.GET_CAMPAIGNS_QUERY,
query = "from CampaignEntity campaign"
),
#NamedQuery(
name = CampaignEntity.DELETE_CAMPAIGNS_QUERY,
query = "DELETE FROM CampaignEntity campaign WHERE campaign.campaign_id = :campaign_id"
)
})
#Entity
#Table(name = "campaign")
public class CampaignEntity implements Serializable {
public static final String GET_CAMPAIGNS_QUERY ="getCampaignList";
public static final String DELETE_CAMPAIGNS_QUERY ="deleteCampaignList";
#Id
#Getter
#Setter
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "campaign_id", unique = true, nullable = false)
private int campaign_id;
#Getter
#Setter
#Column(name = "name", unique = true)
#NotEmpty(message="Name field is mandatory.")
private String name;
#Getter
#Setter
#Column(name = "no_of_views")
#NotNull(message="No. of Views field is mandatory.")
private int no_of_views;
#Getter
#Setter
#Column(name = "video_url")
#NotEmpty(message="Video URL field is mandatory.")
private String video_url;
#Getter
#Setter
#Column(name = "start_date")
#NotEmpty(message="Start Date field is mandatory.")
private String start_date;
#Getter
#Setter
#Column(name = "end_date")
#NotEmpty(message="End Date field is mandatory.")
private String end_date;
#Getter
#Setter
#Column(name = "click_to_play")
#NotNull(message="Click to play field is mandatory.")
private int click_to_play;
#Getter
#Setter
#Column(name = "frequency")
#NotNull(message="Frequency field is mandatory.")
private int frequency;
#Getter
#Setter
#Column(name = "priority")
#Digits(fraction = 0, integer = 100)
#NotNull(message="Priority field is mandatory.")
private int priority;
#Getter
#Setter
#Column(name = "divice")
#NotNull(message="Divice field is mandatory.")
private int divice;
#Getter
#Setter
#Column(name = "operating_system")
#NotNull(message="Operating system field is mandatory.")
private int operating_system;
#Getter
#Setter
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "publisher_id")
#NotEmpty(message="Publisher field is mandatory.")
private PublisherEntity publishers;
#Getter
#Setter
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "agency_id")
#NotEmpty(message="Agency field is mandatory.")
private AgencyEntity agencies;
}
my validator class is
package com.nativeunlock.Validator;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import com.nativeunlock.dto.CampaignEntity;
#Component
public class CampaignValidator implements Validator{
#Override
public boolean supports(Class c) {
return CampaignEntity.class.isAssignableFrom(c);
}
#Override
public void validate(Object command, Errors errors) {
CampaignEntity campaignBean = (CampaignEntity)command;
/*if(!regBean.getPassword().equals(regBean.getRePassword()))
errors.rejectValue("rePassword","password.notmatch");*/
}
}
The problem is that by adding a model attribute model.addAttribute("Campaign", campaignBean); you're removing your binding errors from the model.
Binding errors are bound to the validated instance. If you set a breakpoint to a first line inside your method and inspect a model, you will see a validated object with the key Campaign, but also a binding error object with the key org.springframework.validation.BindingResult.Campaign
When you move further, and reach a point where you're adding a new instance to the model under a 'Campaign' key, notice that the binding errors will get removed from the model, since the instance they're bound is no longer existing, and that is why you don't see them in your JSP.
Remove the model.addAttribute("Campaign", campaignBean); or change the key, and you should see your binding erros.
Also not that you don't need the manual invocation validator.validate(campaignObj, result); the #Valid will call the validation for you

Specifying distinct sequence per table in Hibernate on subclasses

Is there a way to specify distinct sequences for each table in Hibernate, if the ID is defined on a mapped superclass?
All entities in our application extend a superclass called DataObject like this:
#MappedSuperclass
public abstract class DataObject implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "id")
private int id;
}
#Entity
#Table(name = "entity_a")
public class EntityA extends DataObject { ... }
#Entity
#Table(name = "entity_b")
public class EntityB extends DataObject { ... }
This causes all entities to use a shared sequence, the default hibernate_sequence.
What I would like to do is use a separate sequence for each entity, for example entity_a_sequence and entity_b_sequence in the example above. If the ID were specified on the subclasses then I could use the #SequenceGenerator annotation to specify a sequence for each entity, but in this case the ID is on the superclass. Given that ID is in the superclass, is there a way I can use a separate sequence for each entity — and if so, how?
(We are using PostgreSQL 8.3, in case that's relevant)
Have you tried doing it this way ?
#MappedSuperclass
public abstract class DataObject implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idgen")
#Column(name = "id")
private int id;
}
#Entity
#SequenceGenerator(initialValue = 1, name = "idgen", sequenceName = "entityaseq")
#Table(name = "entity_a")
public class EntityA extends DataObject {
}
#Entity
#SequenceGenerator(initialValue = 1, name = "idgen", sequenceName = "entitybseq")
#Table(name = "entity_b")
public class EntityB extends DataObject {
}
I'm sorry I don't have the required environment to test it right now but I'll try it later.
We use this in the abstract superclass of all of our JPA entities:
#Id
#GeneratedValue(generator = "pooled")
#GenericGenerator(name = "pooled", strategy = "org.hibernate.id.enhanced.TableGenerator", parameters = {
#org.hibernate.annotations.Parameter(name = "value_column_name", value = "sequence_next_hi_value"),
#org.hibernate.annotations.Parameter(name = "prefer_entity_table_as_segment_value", value = "true"),
#org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled-lo"),
#org.hibernate.annotations.Parameter(name = "increment_size", value = "100")})
private Long id;
It's a bit verbose, but it allows setting the prefer_entity_table_as_segment_value which means you don't need to repeat the id field or the generator annotations in the subclasses.
I was not quite happy about the need to declare the sequence name on each class individually. I have checked the source code and came up with this solution:
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
// ...
#Id
#GeneratedValue(generator = "sequenceIdGenerator")
#GenericGenerator(
name = "sequenceIdGenerator",
strategy = "sequence",
parameters = #Parameter(
name = SequenceStyleGenerator.CONFIG_PREFER_SEQUENCE_PER_ENTITY,
value = "true"))
#Column(updatable = false, nullable = false)
protected Long id;
IHMO there is better way to do this:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
It works in my app.
TABLE generation stretergy uses separate db sequence for each table but it is little expensive operation

Categories

Resources