I have a problem with my multiselect. I'm using it as an Specification with multiple joins. I don't know why hibernate decides to put a dot in the query. the error is shown below in the query. this is the constructor I'm using
public HelperOutput(Long id,
String personName,
Long helperTypeId,
String helperTypeTitle,
String agencyTitle,
String regionalOfficeTitle,
String basketPartTitle,
YesNo allowedToOperate,
YesNo hasFlatTirePack,
Long fleetRescueId,
Long cityId,
String cityName,
Long skillLevel,
String helperRankTitle,
Long personId,
Long helperRate,
String personelId,
Long regionalOfficeId,
Long basketPartId,
String mobile,
String fleetName,
ExpertType expertType,
Long maxConcurrentWork,
Set<Long> dutyCityIds
) {
this.id = id;
this.helperTypeId = helperTypeId;
this.helperTypeTitle = helperTypeTitle;
this.agencyTitle = agencyTitle;
this.regionalOfficeId = regionalOfficeId;
this.regionalOfficeTitle = regionalOfficeTitle;
this.basketPartTitle = basketPartTitle;
this.fleetRescueId = fleetRescueId;
this.cityId = cityId;
this.helperRankTitle = helperRankTitle;
this.personId = personId;
this.basketPartId = basketPartId;
this.mobile = mobile;
this.fleetName = fleetName;
this.cityName = cityName;
this.personName = personName;
this.allowedToOperate = allowedToOperate;
this.hasFlatTirePack = hasFlatTirePack;
this.skillLevel = skillLevel;
this.helperRate = helperRate;
this.personelId = personelId;
this.expertType = expertType;
this.maxConcurrentWork = maxConcurrentWork;
this.dutyCityIds = dutyCityIds;
}
this is the multiselect which is similar to the constructor.
cq.multiselect(root.get(Helper_.ID),
personName,
helperHelperTypeJoin.get(HelperType_.ID),
helperHelperTypeJoin.get(HelperType_.TITLE),
helperAgencyJoin.get(Agency_.TITLE),
helperRegionalOfficeJoin.get(RegionalOffice_.TITLE)
, helperBasketPartJoin.get(Basket_.TITLE),
root.get(Helper_.ALLOWED_TO_OPERATE),
root.get(Helper_.HAS_FLAT_TIRE_PACK),
fleetRescueJoin.get(HelperFleet_.ID),
helperCityJoin.get(City_.ID) ,
helperCityJoin.get(City_.NAME),
root.get(Helper_.SKILL_LEVEL),
helperRankJoin.get(HelperRank_.NAME),
helperPersonJoin.get(Person_.ID),
root.get(Helper_.helperRate),
root.get(Helper_.personelId),
helperRegionalOfficeJoin.get(RegionalOffice_.ID),
helperBasketPartJoin.get(Basket_.ID),
helperPersonJoin.get(Person_.MOBILE),
HelperFleetJoin.get(Fleet_.NAME),
root.get(Helper_.EXPERT_TYPE),
root.get(Helper_.MAX_CONCURRENT_WORK),
root.get(Helper_.DUTY_CITIES)
);
this is the hibernate query which I don't know why it has a dot.
select
*
from
( select
helper0_.ID as col_0_0_,
person3_.NAME as col_1_0_,
helpertype7_.ID as col_2_0_,
helpertype7_.TITLE as col_3_0_,
agency2_.TITLE as col_4_0_,
regionalof8_.TITLE as col_5_0_,
basket6_.TITLE as col_6_0_,
helper0_.ALLOWED_TO_OPERATE as col_7_0_,
helper0_.HAS_FLAT_TIRE_PACK as col_8_0_,
helperflee4_.ID as col_9_0_,
city1_.ID as col_10_0_,
city1_.NAME as col_11_0_,
helper0_.SKILL_LEVEL as col_12_0_,
helperrank9_.NAME as col_13_0_,
person3_.ID as col_14_0_,
helper0_.HELPER_RATE as col_15_0_,
helper0_.PERSONELID as col_16_0_,
regionalof8_.ID as col_17_0_,
basket6_.ID as col_18_0_,
person3_.MOBILE as col_19_0_,
fleet5_.NAME as col_20_0_,
helper0_.EXPERT_TYPE as col_21_0_,
helper0_.MAX_CONCURRENT_WORK as col_22_0_,
. as col_23_0_ <----------- this causes the problem
from
OPR.TBL_HELPER helper0_
left outer join
OPR.TBL_CITY city1_
on helper0_.CITY_ID=city1_.ID
left outer join
TBL_AGENCY agency2_
on helper0_.AGENCY_ID=agency2_.ID
left outer join
OPR.TBL_PERSONS person3_
on helper0_.PERSON_ID=person3_.ID
left outer join
OPR.TBL_HELPER_FLEET helperflee4_
on helper0_.HELPER_FLEET_ID=helperflee4_.ID
left outer join
OPR.NOEKHODROEMDAD fleet5_
on helperflee4_.NOEKHODROEMDAD_ID=fleet5_.NOEKHODROEMDADID
left outer join
OPR.TBL_BASKET basket6_
on helper0_.BASKET_PART_ID=basket6_.ID
left outer join
OPR.TBL_HELPER_TYPE helpertype7_
on helper0_.HELPER_TYPE_ID=helpertype7_.ID
left outer join
TBL_REGIONAL_OFFICE regionalof8_
on helper0_.REGIONAL_OFFICE_ID=regionalof8_.ID
left outer join
OPR.TBL_HELPER_RANK helperrank9_
on helper0_.RANK_HELPER_ID=helperrank9_.ID
left outer join
TBL_HELPER_DUTY_CITIES dutycities10_
on helper0_.ID=dutycities10_.DUTY_CITY_ID
left outer join
OPR.TBL_CITY city11_
on dutycities10_.ESTABLISHMENT_CITY_ID=city11_.ID
inner join
TBL_HELPER_DUTY_CITIES dutycities12_
on helper0_.ID=dutycities12_.DUTY_CITY_ID
where
1=1
and 1=1
order by
helper0_.ALLOWED_TO_OPERATE asc,
person3_.NAME asc )
where
rownum <= ?
and at last I get this error when returning an Specification from the predicates I made.
Error:
2022-01-31 15:40:08.419 [http-nio-8082-exec-2] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - ORA-00936: missing expression
2022-01-31 15:40:08.444 [http-nio-8082-exec-2] ERROR com.eki.opr.config.LoggingAspect - ----> #AfterThrowing method: GenericRepository.findAll(..)
2022-01-31 15:40:08.445 [http-nio-8082-exec-2] ERROR com.eki.opr.config.LoggingAspect - ----> detailedMessage: ORA-00936: missing expression
2022-01-31 15:40:08.445 [http-nio-8082-exec-2] ERROR com.eki.opr.config.LoggingAspect - ----> detailedCause: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
2022-01-31 15:40:08.445 [http-nio-8082-exec-2] ERROR com.eki.opr.config.LoggingAspect - ----> #AfterThrowing method: HelperServiceImpl.findByCriteria(..)
2022-01-31 15:40:08.445 [http-nio-8082-exec-2] ERROR com.eki.opr.config.LoggingAspect - ----> detailedMessage: ORA-00936: missing expression
2022-01-31 15:40:08.445 [http-nio-8082-exec-2] ERROR com.eki.opr.config.LoggingAspect - ----> detailedCause: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
2022-01-31 15:40:08.446 [http-nio-8082-exec-2] ERROR com.eki.opr.config.LoggingAspect - ----> #AfterThrowing method: HelperController.show(..)
2022-01-31 15:40:08.446 [http-nio-8082-exec-2] ERROR com.eki.opr.config.LoggingAspect - ----> detailedMessage: ORA-00936: missing expression
2022-01-31 15:40:08.446 [http-nio-8082-exec-2] ERROR com.eki.opr.config.LoggingAspect - ----> detailedCause: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
EDIT
these are the entities:
#Entity(name = "HELPER")
#Table(name = "TBL_HELPER", schema = "OPR")
#EqualsAndHashCode(exclude = {"person", "agency", "helperType", "regionalOffice", "basket_part", "helperRank"})
#ToString(exclude = {"person", "agency", "helperType", "regionalOffice", "basket_part", "helperRank"})
#AllArgsConstructor
public class Helper implements Serializable {
private Long id;
#GenericGenerator(
name = "assigned-sequence",
strategy = "com.eki.opr.utils.StringSequenceIdentifier"
)
#GeneratedValue(
generator = "assigned-sequence",
strategy = GenerationType.AUTO)
private String largeId;
private Long skillLevel;
private Long currentWorkCount;
private Long maxConcurrentWork;
private YesNo allowedToOperate;
private YesNo hasGps;
private YesNo isAutoDialer;
private YesNo isPartSupply;
private YesNo hasFlatTirePack;
private String imei;
private String address;
private String personelId;
private String reservedMobile;
private Person person;
private HelperFleet helperFleet;
private HelperType helperType;
private RegionalOffice regionalOffice;
private Agency agency;
private Basket basket_part;
private Basket basket_tools;
private YesNo hasPos;
private String posSerial;
private HelperRank helperRank;
private Parameter contractType;
private Set<ServiceType> serviceTypes = new HashSet<ServiceType>();
private Long helperRate;
private ExpertType expertType = ExpertType.HELPER;
public Helper() {
}
private City city;
#JoinColumn(name = "CITY_ID", referencedColumnName = "ID")
#ManyToOne(fetch = FetchType.LAZY)
public City getCity() {
return city;
}
public void setCity(City city) {
this.city = city;
}
private Set<HelperDutyCity> dutyCities = new HashSet<>();
/* in this part mappedBy's value should be changed to helper because the
join must be on helper not dutyCityId*/
#OneToMany(targetEntity = HelperDutyCity.class, mappedBy = "dutyCityId", fetch = FetchType.EAGER)
public Set<HelperDutyCity> getDutyCities() {
return dutyCities;
}
public void setDutyCities(Set<HelperDutyCity> dutyCities) {
this.dutyCities = dutyCities;
}
public void setHelperRate(Long helperRate) {
this.helperRate = helperRate;
}
#Column(name = "HELPER_RATE")
public Long getHelperRate() {
return helperRate;
}
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_helper")
#SequenceGenerator(name = "seq_helper", sequenceName = "SA.SEQ_EMDADGAR_ID", allocationSize = 1,initialValue = 63442)
#Column(name = "ID")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "ADDRESS")
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
#Column(name = "SKILL_LEVEL")
public Long getSkillLevel() {
return skillLevel;
}
public void setSkillLevel(Long skillLevel) {
this.skillLevel = skillLevel;
}
#Column(name = "MAX_CONCURRENT_WORK")
public Long getMaxConcurrentWork() {
return maxConcurrentWork;
}
public void setMaxConcurrentWork(Long maxConcurrentWork) {
this.maxConcurrentWork = maxConcurrentWork;
}
#Column(name = "CURRENT_WORK_COUNT")
public Long getCurrentWorkCount() {
return currentWorkCount;
}
public void setCurrentWorkCount(Long currentWorkCount) {
this.currentWorkCount = currentWorkCount;
}
#Column(name = "ALLOWED_TO_OPERATE")
#Convert(converter = YesNoConverter.class)
public YesNo getAllowedToOperate() {
return allowedToOperate;
}
public void setAllowedToOperate(YesNo allowedToOperate) {
this.allowedToOperate = allowedToOperate;
}
#Column(name = "HAS_GPS")
#Convert(converter = YesNoConverter.class)
public YesNo getHasGps() {
return hasGps;
}
public void setHasGps(YesNo hasGps) {
this.hasGps = hasGps;
}
#Column(name = "PART_SUPPLY")
#Convert(converter = YesNoConverter.class)
public YesNo getIsPartSupply() {
return isPartSupply;
}
public void setIsPartSupply(YesNo isPartSupply) {
this.isPartSupply = isPartSupply;
}
#Column(name = "PERSONELID")
public String getPersonelId() {
return personelId;
}
public void setPersonelId(String personelId) {
this.personelId = personelId;
}
#Column(name = "HAS_FLAT_TIRE_PACK")
#Convert(converter = YesNoConverter.class)
public YesNo getHasFlatTirePack() {
return hasFlatTirePack;
}
public void setHasFlatTirePack(YesNo hasFlatTirePack) {
this.hasFlatTirePack = hasFlatTirePack;
}
#Column(name = "IMEI")
public String getImei() {
return imei;
}
public void setImei(String imei) {
this.imei = imei;
}
#JoinColumn(name = "CREATED_BY", referencedColumnName = "ID")
#ManyToOne(fetch = FetchType.LAZY)
private PersonUnion createdBy;
#Column(name = "CREATED_AT")
private LocalDateTime createdAt;
#Column(name = "IS_AUTO_DIALER")
#Convert(converter = YesNoConverter.class)
public YesNo getIsAutoDialer() {
return isAutoDialer;
}
public void setIsAutoDialer(YesNo isAutoDialer) {
this.isAutoDialer = isAutoDialer;
}
#Column(name = "RESERVED_MOBILE")
public String getReservedMobile() {
return reservedMobile;
}
#Column(name = "HAS_POS")
#Convert(converter = YesNoConverter.class)
public YesNo getHasPos() { return hasPos; }
public void setHasPos(YesNo hasPos) {
this.hasPos = hasPos;
}
#Column(name = "POS_SERIAL")
public String getPosSerial() { return posSerial; }
public void setPosSerial(String posSerial) {
this.posSerial = posSerial;
}
public void setReservedMobile(String reservedMobile) {
this.reservedMobile = reservedMobile;
}
#JoinColumn(name = "MODIFIED_BY", referencedColumnName = "ID")
#ManyToOne(fetch = FetchType.LAZY)
private PersonUnion modifiedBy;
#Column(name = "MODIFIED_AT")
private LocalDateTime modifiedAt;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PERSON_ID", referencedColumnName = "ID")
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
#JoinColumn(name = "HELPER_TYPE_ID", referencedColumnName = "ID")
#ManyToOne(fetch = FetchType.LAZY)
public HelperType getHelperType() {
return helperType;
}
public void setHelperType(HelperType helperType) {
this.helperType = helperType;
}
#JoinColumn(name = "REGIONAL_OFFICE_ID", referencedColumnName = "ID")
#ManyToOne(fetch = FetchType.LAZY)
public RegionalOffice getRegionalOffice() {
return regionalOffice;
}
public void setRegionalOffice(RegionalOffice regionalOffice) {
this.regionalOffice = regionalOffice;
}
#JoinColumn(name = "AGENCY_ID", referencedColumnName = "ID")
#ManyToOne(fetch = FetchType.LAZY)
public Agency getAgency() {
return agency;
}
public void setAgency(Agency agency) {
this.agency = agency;
}
#JoinColumn(name = "BASKET_PART_ID", referencedColumnName = "ID")
#ManyToOne(fetch = FetchType.LAZY)
public Basket getBasket_part() {
return basket_part;
}
public void setBasket_part(Basket basket_part) {
this.basket_part = basket_part;
}
#JoinColumn(name = "BASKET_TOOLS_ID", referencedColumnName = "ID")
#ManyToOne(fetch = FetchType.LAZY)
public Basket getBasket_tools() {
return basket_tools;
}
public void setBasket_tools(Basket basket_tools) {
this.basket_tools = basket_tools;
}
#ManyToOne
#JoinColumn(name = "HELPER_FLEET_ID", referencedColumnName = "ID")
public HelperFleet getHelperFleet() {
return helperFleet;
}
public void setHelperFleet(HelperFleet helperFleet) {
this.helperFleet = helperFleet;
}
#JoinColumn(name = "RANK_HELPER_ID", referencedColumnName = "ID")
#ManyToOne(fetch = FetchType.LAZY)
public HelperRank getHelperRank() {
return helperRank;
}
public void setHelperRank(HelperRank helperRank) {
this.helperRank = helperRank;
}
#Column(name = "LARGE_ID")
public String getLargeId(){return this.largeId;}
public void setLargeId(String largeId){this.largeId = largeId;}
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "TBL_HELPER_SERVICE_TYPE", uniqueConstraints = {#UniqueConstraint(columnNames = {"HELPER_ID", "SERVICE_TYPE_ID"})},
joinColumns = #JoinColumn(name = "HELPER_ID", referencedColumnName = "ID"),
inverseJoinColumns = #JoinColumn(name = "SERVICE_TYPE_ID", referencedColumnName = "ID"))
public Set<ServiceType> getServiceTypes() {
return serviceTypes;
}
public void setServiceTypes(Set<ServiceType> serviceTypes) {
this.serviceTypes = serviceTypes;
}
#JoinColumn(name = "CONTRACT_TYPE")
#ManyToOne
public Parameter getContractType() {
return contractType;
}
public void setContractType(Parameter contractType){
this.contractType = contractType;
}
#Convert(converter = ExpertTypeConverter.class)
#Column(name = "EXPERT_TYPE")
public ExpertType getExpertType() {
return expertType;
}
public void setExpertType(ExpertType expertType) {
this.expertType = expertType;
}
public void fromDto(HelperInput input) {
this.id = input.getId();
this.address = input.getAddress();
this.allowedToOperate = input.getAllowedToOperate();
this.currentWorkCount = input.getCurrentWorkCount();
this.hasGps = input.getHasGps();
this.hasFlatTirePack = input.getHasFlatTirePack();
this.isAutoDialer = input.getIsAutoDialer();
this.personelId = input.getPersonelId();
this.isPartSupply = input.getIsPartSupply();
this.maxConcurrentWork = input.getMaxConcurrentWork();
this.hasPos = input.getHasPos();
this.posSerial = input.getPosSerial();
this.skillLevel = input.getSkillLevel();
this.reservedMobile = input.getReservedMobile();
if (input.getId() == null) { //first time
this.largeId = StringSequenceIdentifier.generateLargeId();
this.createdBy = input.getCreatedByEntity();
this.createdAt = LocalDateTime.now();
this.modifiedBy = input.getCreatedByEntity();
this.modifiedAt = createdAt;
} else {
this.modifiedBy = input.getModifiedByEntity();
this.modifiedAt = LocalDateTime.now();
}
this.helperRate = input.getHelperRate();
}
}
#Entity
#Getter
#Setter
#NoArgsConstructor
#ToString
#AllArgsConstructor
#JsonDeserialize
#Table(name = "TBL_HELPER_DUTY_CITIES")
#IdClass(HelperDutyCityKey.class)
public class HelperDutyCity implements Serializable {
#Id
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "HELPER_ID")
private Helper helper;
#Id
#OneToOne
#JoinColumn(name = "ESTABLISHMENT_CITY_ID", referencedColumnName = "ID")
#Fetch(FetchMode.JOIN)
private City establishmentCityId;
#ManyToOne
#JoinColumn(name = "DUTY_CITY_ID", referencedColumnName = "ID")
#Fetch(FetchMode.JOIN)
private City dutyCityId;
public HelperDutyCity(Helper helper, City establishmentCityId) {
this.helper = helper;
this.establishmentCityId = establishmentCityId;
}
}
#Data
#ToString(exclude = {"regions","regionalOffice", "province","productCities"})
#EqualsAndHashCode(exclude = {"regions","regionalOffice", "province","productCities"})
#JsonInclude(JsonInclude.Include.NON_NULL)
#Entity
#Table(name = "TBL_CITY", schema = "OPR")
public class City implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#GenericGenerator(
name = "seqCity",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
#org.hibernate.annotations.Parameter(name = "sequence_name", value = "SEQ_CITY"),
#org.hibernate.annotations.Parameter(name = "initial_value", value = "100219"),
#org.hibernate.annotations.Parameter(name = "increment_size", value = "1")
}
)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seqCity")
#Id
#Column(name = "ID")
private Long id;
#Column(name = "NAME")
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PROVINCE_ID", nullable = false)
private Province province;
#GenericGenerator(
name = "assigned-sequence",
strategy = "com.eki.opr.utils.StringSequenceIdentifier"
)
#GeneratedValue(
generator = "assigned-sequence",
strategy = GenerationType.SEQUENCE)
#Column(name = "LARGE_ID")
private String largeId;
#Column(name = "OPR_SHAHR_ID")
private Double oprCityId;
#Column(name = "LATITUDE")
private Double latitude;
#Column(name = "LONGITUDE")
private Double longitude;
#Column(name = "METROPOLIS_FACTOR")
private Double metropolisFactor;
#Convert(converter = YesNoConverter.class)
#Column(name = "IS_AUTOMATED_DISPATCH")
private YesNo isAutomatedDispatch;
#Convert(converter = GeneralStatusConverter.class)
#Column(name = "STATUS")
private GeneralStatus status;
#Column(name = "PARSIMAP_CITY_CODE")
private String parsiMapCityCode;
#Column(name = "AMAR_CITY_CODE")
private String parsiMapCityAmarCode;
#JoinColumn(name = "REGIONAL_OFFICE_ID")
#ManyToOne(fetch = FetchType.LAZY)
private RegionalOffice regionalOffice;
#ManyToMany(
fetch = FetchType.LAZY, mappedBy = "cities")
Set<Region> regions = new HashSet<>();
/* #OneToMany(mappedBy = "city")
private Set<Address> addresses;*/
public City() {
}
public City(Long id) {
this.id = id;
// this.addresses = addresses;
}
public City(CityDto dto) {
fromDto(dto);
}
public void fromDto(CityDto cityDto) {
this.name = cityDto.getName();
this.metropolisFactor = cityDto.getMetropolisFactor();
}
public CityDto toDto() {
CityDto dto = new CityDto();
dto.setId(id);
dto.setName(name);
dto.setMetropolisFactor(metropolisFactor);
dto.setProvinceDto(province.toDto());
dto.setRegionalOfficeOutput(regionalOffice.toDto());
return dto;
}
public CityLite toDtoLite() {
CityLite dto = new CityLite();
dto.setId(id);
dto.setName(name);
dto.setMetropolisFactor(metropolisFactor);
dto.setProvinceId(province != null ? province.getId() : null);
dto.setProvinceName(province != null ? province.getName() : "");
dto.setRegionalOfficeId(regionalOffice != null ? regionalOffice.getId() : null);
dto.setRegionalOfficeTitle(regionalOffice != null ? regionalOffice.getTitle() : "");
dto.setParsiMapCityCode(parsiMapCityCode);
dto.setParsiMapAmarCityCode(parsiMapCityAmarCode);
dto.setLat(latitude != null ? latitude :0);
dto.setLng(longitude != null ? longitude :0);
return dto;
}
}
I answered it in a comment in Helper entity. the answer is you shouldn't make a mistake in mappedBy attribute in #OneToMany annotation. so I changed dutyCityId to helper now it's working.
before it was joining with another condition helper.ID = helperDutyCity.dutyCityId which was wrong now it joins with this condition helper.ID = helperDutyCity.helperId which is correct.
I have something similar to this:
#Entity
#Table(name = "claim", schema = "test")
public class Claim implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idClaim", unique = true, nullable = false)
private Integer idClaim;
#OneToOne(mappedBy = "claim", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JsonManagedReference
private ClaimReturnInfo claimReturnInfo;
#Column(name = "notes")
private String notes;
// Getters and setters
}
#Entity
#Table(name = "claim_returninfo", schema = "test")
public class ClaimReturnInfo implements Serializable {
#Id
#Column(name = "Claim_idClaim")
private Integer id;
#MapsId("Claim_idClaim")
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "Claim_idClaim")
#JsonBackReference
private Claim claim;
#Column(name = "description")
private String description;
// Getters and setters
}
ClaimReturnInfo Id is not autogenerated because we want to propagate the Id from its parent (Claim). We are not able to do this automatically and we are getting this error: ids for this class must be manually assigned before calling save() when 'cascade' is executed in ClaimReturnInfo .
Is it possible to map Claim Id into ClaimReturnInfo Id or should we do this manually?
Even if we set this ID manually on claimReturnInfo and we can perform updates, we still get this error when trying to create a new Claim:
// POST -> claimRepository.save() -> Error
{
"notes": "Some test notes on a new claim",
"claimReturnInfo": {
"description": "Test description for a new claimReturnInfo"
}
}
In the ServiceImplemetation:
#Override
#Transactional
public Claim save(Claim claim) throws Exception {
if(null != claim.getClaimReturnInfo()) {
claim.getClaimReturnInfo().setId(claim.getIdClaim());
}
Claim claimSaved = claimRepository.save(claim);
return claimSaved;
}
I have tried using the following mappings and from your comments it was apparent that Json object is populated correctly.
I have noticed that the annotation #MapsId is the culprit.If you check the documentation of #MapsId annotation it says
Blockquote
The name of the attribute within the composite key
* to which the relationship attribute corresponds. If not
* supplied, the relationship maps the entity's primary
* key
Blockquote
If you change #MapsId("Claim_idClaim") to #MapsId it will start persisting your entities.
import javax.persistence.*;
#Entity
#Table(name = "CLAIM")
public class Claim {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idClaim", unique = true, nullable = false)
private Long idClaim;
#Column(name = "notes")
private String notes;
#OneToOne(mappedBy = "claim", cascade = CascadeType.ALL, optional = false)
private ClaimReturnInfo claimReturnInfo;
public Long getIdClaim() {
return idClaim;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
public ClaimReturnInfo getClaimReturnInfo() {
return claimReturnInfo;
}
public void setClaimReturnInfo(ClaimReturnInfo claimReturnInfo) {
if (claimReturnInfo == null) {
if (this.claimReturnInfo != null) {
this.claimReturnInfo.setClaim(null);
}
} else {
claimReturnInfo.setClaim(this);
}
this.claimReturnInfo = claimReturnInfo;
}
}
package com.hiber.hiberelations;
import javax.persistence.*;
#Entity
#Table(name = "CLAIM_RETURN_INFO")
public class ClaimReturnInfo {
#Id
#Column(name = "Claim_idClaim")
private Long childId;
#Column(name = "DESCRIPTION")
private String description;
#MapsId
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "Claim_idClaim")
private Claim claim;
public Long getChildId() {
return childId;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Claim getClaim() {
return this.claim;
}
public void setClaim(Claim claim) {
this.claim = claim;
}
}
The eclipse link throws the following error during app initialization
I cannot find the reason, despite the thorough search here.
This is the Error:
Caused by: Exception [EclipseLink-7244]
(Eclipse Persistence Services - 2.6.1.qualifier): org.eclipse.persistence.exceptions.ValidationException
Exception Description:
An incompatible mapping has been encountered between [class User] and [class UserAuthProvider]. This usually occurs when the cardinality of a mapping does not correspond with the cardinality of its backpointer.
at org.eclipse.persistence.exceptions.ValidationException.invalidMapping(ValidationException.java:1296)
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ManyToManyAccessor.process(ManyToManyAccessor.java:158)
at org.eclipse.persistence.internal.jpa.metadata.MetadataProject.processNonOwningRelationshipAccessors(MetadataProject.java:1628)
at org.eclipse.persistence.internal.jpa.metadata.MetadataProject.processStage3(MetadataProject.java:1917)
at org.eclipse.persistence.internal.jpa.metadata.MetadataProcessor.processORMMetadata(MetadataProcessor.java:577)
at org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.processORMetadata(PersistenceUnitProcessor.java:604)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1943)
... 48 more
My Classes.
User
#Entity
#Table(name = "users")
#XmlRootElement
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 255)
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Id
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 255)
#Column(name = "username")
private String username;
#Size(max = 512)
#Column(name = "password")
private char[] password;
#Column(name = "enabled")
private Boolean enabled;
#ManyToOne
#JoinColumn(name = "user_role")
private Role role;
#ManyToMany(mappedBy = "users")
private Collection<UserAuthProvider> authProviders;
#OneToOne(mappedBy = "user", cascade = CascadeType.PERSIST)
#NotNull
private UserInfo userInfo;
#Column(name = "firstname")
private String firstName;
#Column(name = "lastname")
private String lastName;
#Column(name = "displayname")
private String displayName;
#Column(name = "gender")
private Gender gender;
#Column(name = "address", length = 512)
private String address;
#Column(name = "address_geo", length = 512)
private String addressGeo;
#Temporal(javax.persistence.TemporalType.DATE)
#Column(name = "birthdate")
private Date birthDate;
#Temporal(javax.persistence.TemporalType.DATE)
#Column(name = "date_created")
private Date dateCreated;
#Temporal(javax.persistence.TemporalType.DATE)
#Column(name = "date_modified")
private Date dateModified;
public enum Gender {
MALE, FEMALE, UNKNOWN
}
public User() {
gender = Gender.UNKNOWN;
Locale greekLocale = new Locale("el");
dateCreated = Calendar.getInstance(greekLocale).getTime();
enabled = true;
authProviders = new HashSet<>();
userInfo = new UserInfo(this);
}
public User(String username) {
this();
this.username = username;
}
public User(String username, char[] password) {
this();
this.username = username;
this.password = password;
}
//getters and setters
#Override
public int hashCode() {
int hash = 0;
hash += (username != null ? username.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof User)) {
return false;
}
User other = (User) object;
if ((this.username != null && other.username != null) && (this.username.equals(other.username))) {
return true;
}
return true;
}
}
UserAuthProvider
#Entity
#Table(name = "user_auth_provider")
#XmlRootElement
public class UserAuthProvider implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Long id;
#Basic(optional = false)
#Column(name = "providername")
private String providerName;
#Basic(optional = true)
#ManyToMany
#JoinTable(
name = "auth_providers_per_user",
joinColumns = {
#JoinColumn(name = "auth_provider_id", referencedColumnName = "id")},
inverseJoinColumns = {
#JoinColumn(name = "username", referencedColumnName = "username")})
private Collection<User> users;
#Temporal(javax.persistence.TemporalType.DATE)
#Column(name = "date_created")
private Date dateCreated;
#Temporal(javax.persistence.TemporalType.DATE)
#Column(name = "date_modified")
private Date dateModified;
#Column(name = "enabled")
private Boolean enabled;
public UserAuthProvider() {
Locale greekLocale = new Locale("el");
dateCreated = Calendar.getInstance(greekLocale).getTime();
users = new HashSet<>();
enabled = true;
}
#Override
public int hashCode() {
int hash = 5;
hash = 11 * hash + Objects.hashCode(this.id);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final UserAuthProvider other = (UserAuthProvider) obj;
if (!Objects.equals(this.id, other.id)) {
return false;
}
return true;
}
}
Any help would be valuable, thank you
Remove #Basic from all of your association mappings. #Basic is intended to be used with primitive fields. From http://en.wikibooks.org/wiki/Java_Persistence/Basic_Attributes
A basic attribute is one where the attribute class is a simple type such as String, Number, Date or a primitive. A basic attribute's value can map directly to the column value in the database.
I'm trying to get the hang of Hibernate.
After getting my project to compile, I've started to convert my classes to be "Hibernate-enabled"
Currently, I'm having 2 classes
1) Person (id, name, firstname, ...)
2) Task (Id, name, description, idOwner)
I would like to have a OneToMany relationship between Person(id) and Task (idOwner)
So when the users gets the List from the Person class, they would get all the tasks linked to that.
After some trying and failing, here's my current code:
Person.java
#Entity
#Table(name = "people", uniqueConstraints = {
#UniqueConstraint(columnNames = "PERSON_ID")
})
public class Person implements Serializable {
private int id;
private String firstName;
private String name;
private String function;
private String email;
private String password;
private RoleEnum role;
private List<Task> lstTasks;
public Person(String firstName, String name, String function) {
this.firstName = firstName;
this.name = name;
this.function = function;
this.email = "";
this.password = "";
this.setRole(RoleEnum.User);
}
// <editor-fold defaultstate="collapsed" desc="Getters">
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "PERSON_ID", unique = true, nullable = false)
public int getId() {
return id;
}
#Column(name = "PERSON_FIRSTNAME", unique = false, nullable = false, length = 30)
public String getFirstName() {
return firstName;
}
#Column(name = "PERSON_NAME", unique = false, nullable = false, length = 30)
public String getName() {
return name;
}
#Column(name = "PERSON_FUNCTION", unique = false, nullable = false, length = 30)
public String getFunction() {
return function;
}
#Column(name = "PERSON_EMAIL", unique = false, nullable = false, length = 30)
public String getEmail() {
return email;
}
#Column(name = "PERSON_PASSWORD", unique = false, nullable = false, length = 30)
public String getPassword() {
return password;
}
#Column(name = "PERSON_ROLE", unique = false, nullable = false, length = 30)
public RoleEnum getRole() {
return role;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "idOwner")
public List<Task> getLstTasks() {
return lstTasks;
}
//Setters
}
Task.java
#Entity
#Table(name="tasks", uniqueConstraints =
#UniqueConstraint(columnNames = "TASK_ID"))
public class Task implements Serializable {
private int id;
private String name;
private String description;
private int idOwner;
public Task(int id, String name, int idOwner) {
this.id = id;
this.name = name;
this.idOwner = idOwner;
}
// <editor-fold defaultstate="collapsed" desc="Getters">
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "TASK_ID", unique = true, nullable = false)
public int getId() {
return id;
}
#Column(name = "TASK_NAME")
public String getName() {
return name;
}
#Column(name = "TASK_DESCRIPTION")
public String getDescription() {
return description;
}
#Column(name = "TASK_ID_OWNER")
public int getIdOwner() {
return idOwner;
}
// </editor-fold>
//Setters
}
Can somebody tell/show/explain me what I have to do exactly, to make this work?
Currently your mapping should linking ownerId instead of Task class.
Change your Task class to this
private Person person;
#ManyToOne
#JoinColumn(name = "TASK_ID_OWNER")
public Person getPerson() {
return person;
}
In your Person entity you have declared one-to-many relationship with Task entity like this:
#OneToMany(fetch = FetchType.LAZY, mappedBy = "idOwner")
public List<Task> getLstTasks() {
return lstTasks;
}
Here you have given idOwner to mappedBy attribute, it means you are telling hibernate that there is property in Task class called idOwner which is of type Person.
So you have to modify your Tasks class like this (Changing the variable type from int to Person):
private Person idOwner;
#ManyToOne
#JoinColumn(name = "TASK_ID_OWNER")
public Person getIdOwner() {
return idOwner;
}
public void setIdOwner(Person idOwner) {
this.idOwner=idOwner;
}
If you remove the #JoinColumn annotation then hibernate will create a Join table for your relationship, else it will just create a foreign key in Task table with foreign key column name as TASK_ID_OWNER.
I'm new to hibernate 4 and I'm having some problem while saving a object using save(Object) method. My mapping files generated using reverse engineering are give below.
Event.java
#Entity
#Table(name = "event")
public class Event implements java.io.Serializable {
private Integer eventId;
private Set<EventCategory> eventCategories = new HashSet<EventCategory>(0);
public Event() {
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "EVENT_ID", unique = true, nullable = false)
public Integer getEventId() {
return this.eventId;
}
public void setEventId(Integer eventId) {
this.eventId = eventId;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "event")
public Set<EventCategory> getEventCategories() {
return this.eventCategories;
}
public void setEventCategories(Set<EventCategory> eventCategories) {
this.eventCategories = eventCategories;
}
}
category.java
#Entity
#Table(name = "category")
public class Category implements java.io.Serializable {
private Integer categoryId;
private Set<EventCategory> eventCategories = new HashSet<EventCategory>(0);
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "CATEGORY_ID", unique = true, nullable = false)
public Integer getCategoryId() {
return this.categoryId;
}
public void setCategoryId(Integer categoryId) {
this.categoryId = categoryId;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "category")
public Set<EventCategory> getEventCategories() {
return this.eventCategories;
}
public void setEventCategories(Set<EventCategory> eventCategories) {
this.eventCategories = eventCategories;
}
}
EventCategory.java
#Entity
#Table(name = "event_category")
public class EventCategory implements java.io.Serializable {
private EventCategoryId id;
private Event event;
private Category category;
public EventCategory() {
}
public EventCategory(EventCategoryId id) {
this.id = id;
}
public EventCategory(EventCategoryId id, Event event, Category category) {
this.id = id;
this.event = event;
this.category = category;
}
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "eventId", column = #Column(name = "EVENT_ID")),
#AttributeOverride(name = "categoryId", column = #Column(name = "CATEGORY_ID")) })
public EventCategoryId getId() {
return this.id;
}
public void setId(EventCategoryId id) {
this.id = id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "EVENT_ID", insertable = false, updatable = false)
public Event getEvent() {
return this.event;
}
public void setEvent(Event event) {
this.event = event;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CATEGORY_ID", insertable = false, updatable = false)
public Category getCategory() {
return this.category;
}
public void setCategory(Category category) {
this.category = category;
}
}
All these files are generated using hbm2java (reverse engineering). But i couldn't able to save values using the below code. And also I'm not getting any exception while running this piece of code.
EventCategory eventCategory = new EventCategory();
eventCategory.setEvent(event);
eventCategory.setCategory(category);
eventCategory.setId(eventCategoryId);
getSession().save( eventCategory );
Please help me to resolve my problem
You need a transaction.
EventCategory eventCategory = new EventCategory();
eventCategory.setEvent(event);
eventCategory.setCategory(category);
eventCategory.setId(eventCategoryId);
Session session = getSession();
Transaction transaction = session.beginTransaction();
session.save( eventCategory );
transaction.commit();