Hibernate 5 update after insert - java

I'm upgrading my Hibernate version from 3 to 5. Now I have a few tests that fall with an error:
Caused by: java.sql.BatchUpdateException: The UPDATE statement conflicted with the FOREIGN KEY constraint "application_dme_provider_fk1". The conflict occurred in database "ruslans_00_develop_dev_easycare", table "dbo.application", column 'application_code'.
It occurs when an entity Organisation is saving.
Debug logs show this:
2019-01-22 07:17:14,962 DEBUG [main] SQL - insert into organization (country_code, organization_name, party_id) values (?, ?, ?)
2019-01-22 07:17:14,984 DEBUG [main] SQL - select partyrole0_.party_id as party_id2_109_0_, partyrole0_.party_role_type_code as party_ro1_109_0_ from party_role partyrole0_ where partyrole0_.party_id=? and partyrole0_.party_role_type_code=?
2019-01-22 07:17:14,988 DEBUG [main] SQL - insert into party_role (party_id, party_role_type_code) values (?, ?)
2019-01-22 07:17:15,011 DEBUG [main] SQL - select dmeprovide0_.party_id as party_id1_39_0_, dmeprovide0_.party_role_type_code as party_ro2_39_0_, dmeprovide0_.national_provider_identifier as national3_39_0_ from dme_provider dmeprovide0_ where dmeprovide0_.party_id=? and dmeprovide0_.party_role_type_code=?
2019-01-22 07:17:15,018 DEBUG [main] SQL - insert into dme_provider (national_provider_identifier, party_id, party_role_type_code) values (?, ?, ?)
2019-01-22 07:17:15,953 DEBUG [main] SQL - select organisati0_.id as id1_102_4_, organisati0_.account_number as account_2_102_4_, organisati0_.country_code as country13_102_4_, organisati0_.default_billing_plan_id as default14_102_4_, organisati0_.default_plan_updated_by as default15_102_4_, organisati0_.image_id as image_i16_102_4_, organisati0_.name as name3_102_4_, organisati0_.password_reset_duration_months as password4_102_4_, organisati0_.password_reset_required as password5_102_4_, organisati0_.patient_group_layout_code as patient17_102_4_, organisati0_.physician_access as physicia6_102_4_, organisati0_.default_plan_updated_on as default_7_102_4_, organisati0_.primary_contact_information_id as primary18_102_4_, organisati0_.first_name as first_na8_102_4_, organisati0_.last_name as last_nam9_102_4_, organisati0_.title as title10_102_4_, organisati0_.subscription_level as subscri11_102_4_, organisati0_.type as type12_102_4_, applicatio1_.organisation_id as organisa6_12_6_, applicatio1_.application_code as applicat1_12_6_, applicatio1_.party_id as party_id5_12_6_, applicatio1_.party_role_type_code as party_ro2_12_6_, applicatio1_.application_code as applicat1_6_, applicatio1_.application_code as applicat1_12_0_, applicatio1_.party_id as party_id5_12_0_, applicatio1_.party_role_type_code as party_ro2_12_0_, applicatio1_.is_activating_flag as is_activ3_12_0_, applicatio1_.migrated_to_budapest_flag as migrated4_12_0_, applicatio1_.organisation_id as organisa6_12_0_, image2_.id as id1_79_1_, image2_.description as descript2_79_1_, image2_.image as image3_79_1_, image2_.name as name4_79_1_, image2_.type as type5_79_1_, contactinf3_.id as id1_27_2_, contactinf3_.address_id as address13_27_2_, contactinf3_.email as email2_27_2_, contactinf3_.phone_number_0 as phone_nu3_27_2_, contactinf3_.phone_type_0 as phone_ty4_27_2_, contactinf3_.phone_number_1 as phone_nu5_27_2_, contactinf3_.phone_type_1 as phone_ty6_27_2_, contactinf3_.phone_number_2 as phone_nu7_27_2_, contactinf3_.phone_type_2 as phone_ty8_27_2_, contactinf3_.phone_number_3 as phone_nu9_27_2_, contactinf3_.phone_type_3 as phone_t10_27_2_, contactinf3_.phone_number_4 as phone_n11_27_2_, contactinf3_.phone_type_4 as phone_t12_27_2_, contactinf3_.time_zone_code as time_zo14_27_2_, address4_.id as id1_1_3_, address4_.address_line1 as address_2_1_3_, address4_.address_line2 as address_3_1_3_, address4_.city_suburb as city_sub4_1_3_, address4_.country_code as country_6_1_3_, address4_.postcode as postcode5_1_3_, address4_.state_id as state_id7_1_3_ from organisation organisati0_ left outer join application_dme_provider applicatio1_ on organisati0_.id=applicatio1_.organisation_id left outer join image image2_ on organisati0_.image_id=image2_.id left outer join contact_information contactinf3_ on organisati0_.primary_contact_information_id=contactinf3_.id left outer join address address4_ on contactinf3_.address_id=address4_.id where organisati0_.id=?
2019-01-22 07:17:15,969 DEBUG [main] SQL - select applicatio0_.application_code as applicat1_12_0_, applicatio0_.party_id as party_id5_12_0_, applicatio0_.party_role_type_code as party_ro2_12_0_, applicatio0_.is_activating_flag as is_activ3_12_0_, applicatio0_.migrated_to_budapest_flag as migrated4_12_0_, applicatio0_.organisation_id as organisa6_12_0_ from application_dme_provider applicatio0_ where applicatio0_.application_code=? and applicatio0_.party_id=? and applicatio0_.party_role_type_code=?
2019-01-22 07:17:15,973 DEBUG [main] SQL - select location0_.id as id1_90_2_, location0_.active as active2_90_2_, location0_.contact_information as contact_4_90_2_, location0_.name as name3_90_2_, location0_.organisation_id as organisa5_90_2_, contactinf1_.id as id1_27_0_, contactinf1_.address_id as address13_27_0_, contactinf1_.email as email2_27_0_, contactinf1_.phone_number_0 as phone_nu3_27_0_, contactinf1_.phone_type_0 as phone_ty4_27_0_, contactinf1_.phone_number_1 as phone_nu5_27_0_, contactinf1_.phone_type_1 as phone_ty6_27_0_, contactinf1_.phone_number_2 as phone_nu7_27_0_, contactinf1_.phone_type_2 as phone_ty8_27_0_, contactinf1_.phone_number_3 as phone_nu9_27_0_, contactinf1_.phone_type_3 as phone_t10_27_0_, contactinf1_.phone_number_4 as phone_n11_27_0_, contactinf1_.phone_type_4 as phone_t12_27_0_, contactinf1_.time_zone_code as time_zo14_27_0_, address2_.id as id1_1_1_, address2_.address_line1 as address_2_1_1_, address2_.address_line2 as address_3_1_1_, address2_.city_suburb as city_sub4_1_1_, address2_.country_code as country_6_1_1_, address2_.postcode as postcode5_1_1_, address2_.state_id as state_id7_1_1_ from location location0_ left outer join contact_information contactinf1_ on location0_.contact_information=contactinf1_.id left outer join address address2_ on contactinf1_.address_id=address2_.id where location0_.id=?
2019-01-22 07:17:15,983 DEBUG [main] SQL - select billingpla0_.organisation_id as organisa1_15_0_, billingpla0_.billing_plan_id as billing_2_15_0_, billingpla1_.id as id1_14_1_, billingpla1_.allowed_for_all_orgs_flag as allowed_2_14_1_, billingpla1_.card_only_flag as card_onl3_14_1_, billingpla1_.data_start_at_setup_flag as data_sta4_14_1_, billingpla1_.data_start_offset_days as data_sta5_14_1_, billingpla1_.night_profile_duration_days as night_pr6_14_1_, billingpla1_.plan_availability_end_date as plan_ava7_14_1_, billingpla1_.plan_availability_start_date as plan_ava8_14_1_, billingpla1_.plan_code as plan_cod9_14_1_, billingpla1_.plan_duration_days as plan_du10_14_1_, billingpla1_.plan_name as plan_na11_14_1_, billingpla1_.summary_data_duration_days as summary12_14_1_, billingpla1_.troubleshooting_duration_days as trouble13_14_1_, billingpla1_.version as version14_14_1_ from billing_plan_organisation billingpla0_ inner join billing_plan billingpla1_ on billingpla0_.billing_plan_id=billingpla1_.id where billingpla0_.organisation_id=?
2019-01-22 07:17:16,005 DEBUG [main] SQL - select locations0_.organisation_id as organisa5_90_0_, locations0_.id as id1_90_0_, locations0_.id as id1_90_1_, locations0_.active as active2_90_1_, locations0_.contact_information as contact_4_90_1_, locations0_.name as name3_90_1_, locations0_.organisation_id as organisa5_90_1_, contactinf1_.id as id1_27_2_, contactinf1_.address_id as address13_27_2_, contactinf1_.email as email2_27_2_, contactinf1_.phone_number_0 as phone_nu3_27_2_, contactinf1_.phone_type_0 as phone_ty4_27_2_, contactinf1_.phone_number_1 as phone_nu5_27_2_, contactinf1_.phone_type_1 as phone_ty6_27_2_, contactinf1_.phone_number_2 as phone_nu7_27_2_, contactinf1_.phone_type_2 as phone_ty8_27_2_, contactinf1_.phone_number_3 as phone_nu9_27_2_, contactinf1_.phone_type_3 as phone_t10_27_2_, contactinf1_.phone_number_4 as phone_n11_27_2_, contactinf1_.phone_type_4 as phone_t12_27_2_, contactinf1_.time_zone_code as time_zo14_27_2_, address2_.id as id1_1_3_, address2_.address_line1 as address_2_1_3_, address2_.address_line2 as address_3_1_3_, address2_.city_suburb as city_sub4_1_3_, address2_.country_code as country_6_1_3_, address2_.postcode as postcode5_1_3_, address2_.state_id as state_id7_1_3_, timezone3_.time_zone_code as time_zon1_144_4_, timezone3_.time_zone_name as time_zon2_144_4_ from location locations0_ left outer join contact_information contactinf1_ on locations0_.contact_information=contactinf1_.id left outer join address address2_ on contactinf1_.address_id=address2_.id left outer join time_zone timezone3_ on contactinf1_.time_zone_code=timezone3_.time_zone_code where locations0_.organisation_id=? order by locations0_.name
2019-01-22 07:17:16,015 DEBUG [main] SQL - insert into application_dme_provider (is_activating_flag, migrated_to_budapest_flag, organisation_id, application_code, party_id, party_role_type_code) values (?, ?, ?, ?, ?, ?)
2019-01-22 07:17:16,021 DEBUG [main] SQL - update application_dme_provider set application_code=? where application_code=? and party_id=? and party_role_type_code=?
2019-01-22 07:17:16,030 ERROR [main] BatchingBatch - HHH000315: Exception executing batch [java.sql.BatchUpdateException: The UPDATE statement conflicted with the FOREIGN KEY constraint "application_dme_provider_fk1". The conflict occurred in database "ruslans_00_develop_dev_easycare", table "dbo.application", column 'application_code'.], SQL: update application_dme_provider set application_code=? where application_code=? and party_id=? and party_role_type_code=?
2019-01-22 07:17:16,031 ERROR [main] SqlExceptionHelper - The UPDATE statement conflicted with the FOREIGN KEY constraint "application_dme_provider_fk1". The conflict occurred in database "ruslans_00_develop_dev_easycare", table "dbo.application", column 'application_code'.
Organisation class
#Entity(name = "Organisation")
#Table(name = "organisation", uniqueConstraints = {#UniqueConstraint(name = "organisation_name_udx", columnNames = {"name"})})
#NoArgsConstructor
#EntityListeners(EntityCreateListener.class)
public class Organisation implements Serializable, PatientListEntity {
public static final SubscriptionLevel DEFAULT_SUBSCRIPTION_LEVEL = SubscriptionLevel.BASIC;
public static final int NUMBER_OF_DAYS_IN_MONTH = 30;
public static final int MAX_NAME_LENGTH = 50;
public static final int MAX_ACCOUNT_NUMBER_LENGTH = 50;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Getter
#Setter
private Long id;
// Some fields
#Getter
#OneToMany(mappedBy = "organisation", orphanRemoval = true, cascade = CascadeType.ALL)
#MapKeyColumn(name = "application_code")
#JsonManagedReference
private Map<ApplicationEnum, ApplicationDmeProvider> applicationDmeProviderMap = new HashMap<>();
// Some fields
}
ApplicationDmeProvider class
#Entity
#Table(name = "application_dme_provider")
#Getter
#Data
#Builder
#NoArgsConstructor(access = AccessLevel.PROTECTED)
#AllArgsConstructor
#EqualsAndHashCode
public class ApplicationDmeProvider implements Serializable {
#EmbeddedId
private ApplicationDmeProviderId applicationDmeProviderId;
#ManyToOne
#JoinColumn(name = "organisation_id")
#JsonBackReference
private Organisation organisation;
#Type(type = "yes_no")
#Column(name = "migrated_to_budapest_flag")
private boolean migrated;
#Type(type = "yes_no")
#Column(name = "is_activating_flag")
#JsonIgnore
private boolean activating;
}
ApplicationDmeProviderId class
#Data
#NoArgsConstructor
#Embeddable
#AllArgsConstructor
public class ApplicationDmeProviderId implements Serializable {
#Column(name = "application_code")
#Enumerated(EnumType.STRING)
private ApplicationEnum applicationCode;
#JsonBackReference
#Embedded
private PartyRoleId partyRoleId;
}
We checked this test before Hibernate migration and there is no update at all. It looks like Hibernate 5 changed save behavior for this kind of entity.

The problem occurred because of this map applicationDmeProviderMap with ApplicationEnum enum.
The annotation #MapKeyEnumerated(STRING) fixed the problem.

Related

JPA update record is failing due to #OneToMany

I have a very small doubt regarding #OneToMany mapping.
I have a model student and another model attendance.
A student can have multiple attendance. but student model should only be able to retrieve the attendance info.
But when I am trying to change some student info I am getting below error as it is trying to update attendance record.
here is my mapping
#Entity
#Table(name="student_detail")
#Getter #Setter
public class StudentDetailsModel {
#Id
#Column(name="reg_no",updatable = false, nullable = false)
private String regNo;
#OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
#JoinColumn(name = "reg_no")
private List<AttendanceModel> attendances;
}
and the exception I a getting.
update
student_detail
set
address=?,
alt_contact_number=?,
blood_group=?,
contact_number=?,
dob=?,
father_name=?,
first_name=?,
gender=?,
last_name=?,
middle_name=?,
mother_name=?,
photo_url=?,
school_id=?
where
reg_no=?
Hibernate:
update
attendance
set
reg_no=null
where
reg_no=?
2019-01-13 12:12:52.922 WARN 10708 --- [nio-8081-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 23502
2019-01-13 12:12:52.923 ERROR 10708 --- [nio-8081-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: null value in column "reg_no" violates not-null constraint
Detail: Failing row contains (null, 1, 2019-01-05, t, 2).
2019-01-13 12:12:52.926 INFO 10708 --- [nio-8081-exec-1] o.h.e.j.b.internal.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [reg_no]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
my attenance model is as follows
#Entity
#Table(name="attendance")
#Getter #Setter
public class AttendanceModel {
//#EmbeddedId
//private AttendanceId attendanceId;
#Id
#Column(name="attendance_id")
private long id;
#Column(name="reg_no")
private String regNo;
#Column(name="subject_id")
private long subjectId;
#Column(name="class_date")
private Date classDate;
#Column(name="present")
private boolean present;
}
Could you show me Student Model.If i look your code post : You using Unidirectional relationship.
I think it must :
#OneToMany(fetch = FetchType.LAZY , cascade = CascedeType.ALL)
#JoinColumn(name="attendance_id")
private List<AttendanceModel> attendances = new ArrayList<>();

Hibernate not saving into join table - ManyToOne and JoinTable relation

I'm using SpringBoot 2.0.2 with hibernate 5.2.17 and MariaDB 10.1
Customer:
#Entity
public class Customer extends Company {
#ManyToOne(fetch = FetchType.LAZY, cascade = ALL)
#JoinTable(name = "company_services",
joinColumns = #JoinColumn(name = "companyId", insertable = true, updatable = true),
inverseJoinColumns = #JoinColumn(name = "serviceId", insertable = true, updatable = true))
private Service service;
Service:
#Entity
public class Service {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
With Hibernate log enabled I can see this:
Hibernate:
/* insert com.example.company.Customer
*/ insert
into
`
companies` (
...
)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
select
last_insert_id()
Hibernate:
/* insert com.example.company.Customer
*/ insert
into
`
company_service` (
`serviceId`, `companyId`
)
values
(?, ?)
20:43:53.524 TRACE [cid: none] [session: none] org.hibernate.type.descriptor.sql.BasicBinder -- binding parameter [1] as [BIGINT] - [3]
20:43:53.524 TRACE [cid: none] [session: none] org.hibernate.type.descriptor.sql.BasicBinder -- binding parameter [2] as [BIGINT] - [3]
But when I confirm the result in the db the companies table is OK but the company_services record does not get saved.
Is that a known bug? I'm missing something?
Hibernate does not use join table for many to one relationship. It uses a join column for many to one relationship.

Hibernate/JPA - one primary key parent to composite key child

Whats wrong in my jpa mapping, im trying to map the parent class with one primary key to the child class with composite key, but it seems its inserting in the wrong table, it already generate 2 table but unfortunately i didn't bind the foreign key(policy_value_summary_id)
#Entity
#Table(name = "POLICY_VALUE_SUMMARY")
public class PolicyValueSummary {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="POLICY_VALUE_SUMMARY_ID")
private Long policyValueSummaryId;
#MapsId("policyValueSummaryId")
#OneToMany
private Set<PolicyValue> policyValues;
}
the child class have composite keys with one is the parent id.
#Entity
#Table(name = "POLICY_VALUE")
public class PolicyValue {
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "policyValueSummaryId", column = #Column(name = "POLICY_VALUE_SUMMARY_ID")),
#AttributeOverride(name = "planAtrId", column = #Column(name = "PLAN_ATR_ID")) })
private PolicyValuePk policyValuePk;
}
This is my child class composite keys.
#Embeddable
public class PolicyValuePk implements Serializable {
private Long policyValueSummaryId;
private Long planAtrId;
}
Im trying to save the policy summary value(parent) with the policy value(child class) like this
PolicyValuePk pk = new PolicyValuePk();
pk.setPlanAtrId(Long.valueOf("1"));
Set<PolicyValue> policyValues = new HashSet<>();
policyValues.add(new PolicyValue(pk));
PolicyValueSummary summary = new PolicyValueSummary();
summary.setPolicyValues(policyValues);
repo.save(summary);
Here is the error that being output to me
Hibernate: select hibernate_sequence.nextval from dual
Hibernate: insert into policy_value_summary (policy_value_summary_id) values (?)
Hibernate: insert into policy_value_summary_policy_values (policy_value_summary_policy_value_summary_id, policy_values_plan_atr_id, policy_values_policy_value_summary_id) values (?, ?, ?)
WARN 6880 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 972, SQLState: 42000
ERROR 6880 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : ORA-00972: identifier is too long
No, prior to Oracle version 12.2, identifiers are not allowed to exceed 30 characters in length. See the document
http://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements008.htm#SQLRF00223
But from from version 12.2 they can be up to 128 bytes long

JPA / Hibernate "simple" OneToMany Unidirictional / Clear of set does not work

I don't know what I am doing wrong, but apparently I am not able to create a simple OneToMany relationship with hibernate.
Here are my tables how they look in DB:
I will only show relevant part, so the question does not get to bloated.
My User Looks like
#Entity(name = "CORE_USER")
public class User extends AbstractPersistentObject {
...
#ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
#JoinTable(name = "CORE_USER_TO_ROLE",
joinColumns = { #JoinColumn(name = "USER_ID") },
inverseJoinColumns = { #JoinColumn(name = "ROLE_ID") })
private Set<UserRole> roles = new HashSet<UserRole>();
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "USER_ID")
private Set<UserRoleParam> userRoleParams = new HashSet<UserRoleParam>();
...(getter and setters)
}
Here Core user role param entity
#Entity(name = "CORE_USER_ROLE_PARAM")
public class UserRoleParam extends AbstractPersistentObject {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ROLE_ID")
private UserRole userRole;
#Column(name = "ROLE_PARAMETER")
private String paramter;
...(getter and setter)....
}
UserRole entity
#Entity(name="CORE_USER_ROLE")
public class UserRole extends AbstractPersistentObject {
#Enumerated(EnumType.STRING)
#Column(name = "ROLE_NAME", length = 30, nullable=false, unique=true)
private UserRoleEnum roleName;
...(getter and setters)
}
When I do this in my test:
#Test
#Transactional(propagation = Propagation.NEVER)
public void saveUserRoleParametersTest() throws Exception {
// load an user which exists and check params is zero
UserDTO userDTO = userService.getUserDTO(Users.DE678_ACTIVE_ALLROLES.getObject().getId());
Assert.assertNotNull(userDTO);
Assert.assertNotNull(userDTO.getUserRoleParams());
Assert.assertEquals(0, userDTO.getUserRoleParams().size());
Map<UserRoleEnum, List<String>> userRoleParams = new HashMap<>();
userRoleParams.put(UserRoleEnum.BASIC, new ArrayList<>());
userRoleParams.get(UserRoleEnum.BASIC).add("BASIC_PARAM");
// save params to user
userService.saveUserRoleParameters(Users.DE678_ACTIVE_ALLROLES.getObject().getId(), userRoleParams);
userDTO = userService.getUserDTO(Users.DE678_ACTIVE_ALLROLES.getObject().getId());
Assert.assertNotNull(userDTO);
Assert.assertNotNull(userDTO.getUserRoleParams());
Assert.assertEquals(1, userDTO.getUserRoleParams().size());
Assert.assertEquals(1, userDTO.getUserRoleParams().get(UserRoleEnum.BASIC).size());
Assert.assertTrue(userDTO.getUserRoleParams().get(UserRoleEnum.BASIC).contains("BASIC_PARAM"));
// delete params of user
userService.saveUserRoleParameters(Users.DE678_ACTIVE_ALLROLES.getObject().getId(), null);
userDTO = userService.getUserDTO(Users.DE678_ACTIVE_ALLROLES.getObject().getId());
Assert.assertNotNull(userDTO);
Assert.assertNotNull(userDTO.getUserRoleParams());
Assert.assertEquals(0, userDTO.getUserRoleParams().size());
}
here is also the user service method which I invoke:
#Override
public void saveUserRoleParameters(final String userId, final Map<UserRoleEnum, List<String>> userRoleParams) throws UserNotFoundException {
User user = userDAO.get(userId);
if (user == null) {
throw new UserNotFoundException(userId);
}
if (userRoleParams == null || userRoleParams.isEmpty()) {
user.getUserRoleParams().clear();
} else {
List<UserRole> roles = userDAO.getUserRolesByEnums(userRoleParams.keySet());
Map<UserRoleEnum, UserRole> enumToEntity = new HashMap<>();
roles.stream().forEach(r -> enumToEntity.put(r.getRoleName(), r));
for (Entry<UserRoleEnum, List<String>> entry : userRoleParams.entrySet()) {
UserRoleParam urp = new UserRoleParam(enumToEntity.get(entry.getKey()), entry.getValue().stream().collect(Collectors.joining(";")));
user.getUserRoleParams().add(urp);
}
}
userDAO.saveOrUpdate(user);
}
The problem is that my test fails on first service method call of saveUserRoleParameters which is (EDIT: now with sql log enabled):
DEBUG [main] 12.05.17 08:46:50.264 org.hibernate.engine.jdbc.spi.SqlStatementLogger#logStatement: select user0_.id as id1_0_0_, user0_.version as version2_0_0_, user0_.ACTIVE as ACTIVE1_38_0_, user0_.APP_LANG as APP_LANG2_38_0_, user0_.DEFAULT_MODULE as DEFAULT_3_38_0_, user0_.ORGA_UNIT as ORGA_UNI4_38_0_, user0_.USER_FULL_NAME as USER_FUL5_38_0_, user0_.USER_NAME as USER_NAM6_38_0_ from CORE_USER user0_ where user0_.id=?
DEBUG [main] 12.05.17 08:46:50.270 org.hibernate.engine.jdbc.spi.SqlStatementLogger#logStatement: select userrole0_.id as id1_0_, userrole0_.version as version2_0_, userrole0_.ROLE_NAME as ROLE_NAM1_41_ from CORE_USER_ROLE userrole0_ where userrole0_.ROLE_NAME in (?)
DEBUG [main] 12.05.17 08:46:50.287 org.hibernate.engine.jdbc.spi.SqlStatementLogger#logStatement: select userrolepa0_.USER_ID as USER_ID3_0_0_, userrolepa0_.id as id1_42_0_, userrolepa0_.id as id1_0_1_, userrolepa0_.version as version2_0_1_, userrolepa0_.ROLE_PARAMETER as ROLE_PAR1_42_1_, userrolepa0_.ROLE_ID as ROLE_ID2_42_1_ from CORE_USER_ROLE_ROLE_PARAM userrolepa0_ where userrolepa0_.USER_ID=?
DEBUG [main] 12.05.17 08:46:50.290 org.hibernate.engine.jdbc.spi.SqlStatementLogger#logStatement: insert into CORE_USER_ROLE_PARAM (version, ROLE_PARAMETER, ROLE_ID, id) values (?, ?, ?, ?)
WARN [main] 12.05.17 08:46:50.291 org.hibernate.engine.jdbc.spi.SqlExceptionHelper#logExceptions: SQL Error: 23502, SQLState: 23502
ERROR [main] 12.05.17 08:46:50.291 org.hibernate.engine.jdbc.spi.SqlExceptionHelper#logExceptions: NULL nicht zulässig für Feld "USER_ID"
NULL not allowed for column "USER_ID"; SQL statement:
insert into CORE_USER_ROLE_ROLE_PARAM (version, ROLE_PARAMETER, ROLE_ID, id) values (?, ?, ?, ?) [23502-175]
WARN [main] 12.05.17 08:46:50.291 org.hibernate.engine.jdbc.spi.SqlExceptionHelper#logExceptions: SQL Error: 23502, SQLState: 23502
ERROR [main] 12.05.17 08:46:50.292 org.hibernate.engine.jdbc.spi.SqlExceptionHelper#logExceptions: NULL nicht zulässig für Feld "USER_ID"
NULL not allowed for column "USER_ID"; SQL statement:
Shouldn't jpa put the UserId where it belongs? What I want is a Unidirectional relationship where User knows about UserRoleParams but not the other way around. Like in the example here http://www.objectdb.com/api/java/jpa/annotations/relationship
EDIT#2:
I found a solution. I added following on User Entity:
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "USER_ID", nullable = false)
private Set<UserRoleParam> userRoleParams = new HashSet<UserRoleParam>();
Now I have the issue that clearing the set will not be persisted. My test fails as the second check if the Set is empty fails. It shows that the Parameters are still set.
The fields User.userRoleParams and UserRoleParam.user are part of a bidirectional relation. To do that you must add
mappedBy="user" to the #OneToMany side.
You cannot have those two parts as independent relations (i.e unidirectional 1-N and unidirectional N-1) reusing the same FK column ("USER_ID").
As for your documentation you linked to in the comments, the only use of unidirectional 1-N has no field on the other side (and you do have a field on the other side of the relation).
User has changed their question since this answer! Why do I bother?

Constraint Violation when persisting One To Many relation

In a spring mvc application using hibernate and MySQL, I am getting the following constraint violation exception:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
Cannot add or update a child row: a foreign key constraint fails
(`mybd`.`hl7_documententity`, CONSTRAINT `hl7_documententity_ibfk_1`
FOREIGN KEY (`ptcode`, `ptcodesystem`)
REFERENCES `hl7_generalcode` (`code`, `codesystem`))
The problem occurs when I try to save a DocumentEntity containing a property of type GeneralCode, both of which are defined below.
I have read many postings and blogs on this error, but none seem to resolve my problem. How can I resolve this error?
Here is the DocumentEntity class:
#Entity
#Table(name = "hl7_documententity")
public class HL7DocumentEntity extends BaseEntity{
//other properties
#ManyToOne
#JoinColumns({ #JoinColumn(name = "ptcode", referencedColumnName = "code"),
#JoinColumn(name = "ptcodesystem", referencedColumnName = "codesystem")
})
private HL7GeneralCode providertype;
//getters and setters
}
Here is the GeneralCode class:
#Entity
#Table(name = "hl7_generalcodes")
public class HL7GeneralCode implements Serializable{
private static final long serialVersionUID = -8620565054475096516L;
#EmbeddedId
private HL7EmbedCodePK codePk;
#OneToMany(mappedBy = "providertype")
private Set<HL7DocumentEntity> documententities;
////////////getters and setters
}
Here is the code from the controller:
HL7GeneralCode authcode = processGeneralCode(grandkid);
HL7GeneralCode testcode = this.clinicService.findGeneralCodeByPK(authcode.getCodePk().getCode(), authcode.getCodePk().getCodesystem());
if(testcode==null){
authcode.addDocumententity(mydent);
this.clinicService.savehl7GeneralCode(authcode);
mydent.setProvidertype(authcode);
//this next line throws the error
this.clinicService.savehl7DocumentEntity(mydent);
}else{
//other stuff
}
Here is the dao method:
#Repository
public class JpaSomethingRepositoryImpl implements SomethingRepository {
#PersistenceContext
private EntityManager em;
#Override
#Transactional
public void savehl7DocumentEntity(HL7DocumentEntity de) {
HL7GeneralCode code = de.getProvidertype();
if(code !=null && code.getCodePk()==null){//HL7GeneralCode is not persistent. We don't support that
throw new IllegalStateException("Cannot persist an adress using a non persistent HL7GeneralCode");
}
System.out.println("=========================== inside jpaCdaRespository.saveDocEntity(de)");
de.setProvidertype(null);
if(code.getDocumententities()!=null){
ArrayList<HL7DocumentEntity> addrList = new ArrayList<HL7DocumentEntity>();
addrList.addAll(code.getDocumententities());
addrList.remove(de);
Set<HL7DocumentEntity> myaddrs = new HashSet<HL7DocumentEntity>(addrList);
code.setDocumententities(myaddrs);
}
code = em.merge(code);
de.setProvidertype(code);
code.addDocumententity(de);
if (de.getId() == null) {
System.out.println("[[[[[[[[[[[[ about to persist de ]]]]]]]]]]]]]]]]]]]]");
em.persist(de);
} else {
System.out.println("]]]]]]]]]]]]]]]]]] about to merge de [[[[[[[[[[[[[[[[[[[[[");
de = em.merge(de);
}
}
}
The executed SQL statement and the actual values that hibernate is trying to insert via the sql are:
[[[[[[[[[[[[ about to persist de ]]]]]]]]]]]]]]]]]]]]
DEBUG SQL - insert into hl7_documententity (author_id, authpar_id, entitytype, id_extension, id_root, ptcode, ptcodesystem, id) values (?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into hl7_documententity (author_id, authpar_id, entitytype, id_extension, id_root, ptcode, ptcodesystem, id) values (?, ?, ?, ?, ?, ?, ?, ?)
TRACE BasicBinder - binding parameter [1] as [INTEGER] - <null>
TRACE BasicBinder - binding parameter [2] as [INTEGER] - <null>
TRACE BasicBinder - binding parameter [3] as [VARCHAR] - <null>
TRACE BasicBinder - binding parameter [4] as [VARCHAR] - NI
TRACE BasicBinder - binding parameter [5] as [VARCHAR] - nullFlavor
TRACE BasicBinder - binding parameter [6] as [VARCHAR] - UNK
TRACE BasicBinder - binding parameter [7] as [VARCHAR] - HL7NullFlavor
TRACE BasicBinder - binding parameter [8] as [INTEGER] - 32787
WARN SqlExceptionHelper - SQL Error: 1452, SQLState: 23000
ERROR SqlExceptionHelper - Cannot add or update a child row: a foreign key constraint fails (`docbd`.`hl7_documententity`, CONSTRAINT `hl7_documententity_ibfk_1` FOREIGN KEY (`ptcode`, `ptcodesystem`) REFERENCES `hl7_generalcode` (`code`, `codesystem`))
INFO AbstractBatchImpl - HHH000010: On release of batch it still contained JDBC statements
WARN warn - Handler execution resulted in exception
You can read the EmbedCodePK class code by clicking on this link.
You can read the entire stack trace by clicking on this link.
Here is a link to the code for the BaseEntity class.
Change this:
#OneToMany(mappedBy = "providertype")
private Set<HL7DocumentEntity> documententities;
To this:
#OneToMany(fetch = FetchType.LAZY)
#JoinTable(name = "Link_Documents", joinColumns = {#JoinColumn(name = "codePk", unique = true)}, inverseJoinColumns = {#JoinColumn(name = "change_this_with_primary_key_variable_name_from_HL7DocumentEntity")})
private Set<HL7DocumentEntity> documententities;
And in HL7DocumentEntity change as follows:
This
#ManyToOne
#JoinColumns({ #JoinColumn(name = "ptcode", referencedColumnName = "code"),
#JoinColumn(name = "ptcodesystem", referencedColumnName = "codesystem")
})
private HL7GeneralCode providertype;
Change to this:
#ManyToOne(fetch = FetchType.LAZY)
#JoinTable(name = "Link_Documents", joinColumns = {#JoinColumn(name = "change_this_with_primary_key_variable_name_from_HL7DocumentEntity")}, inverseJoinColumns = {#JoinColumn(name = "codePk")})
private HL7GeneralCode providertype;
I think you have to change "change_this_with_primary_key_variable_name_from_HL7DocumentEntity" with "id" like it is in BaseEntity but take a look at your sql table, you willsee there the correct name.
I hope you notice How I told JPA to use the same "Link_Documents" table for linking the 2 tables. I think this is were your mistake is. Just make sure to change where I told you with the correct variable name and I think it should work
you know i would start by cleaning up this code.
Though the hibernate documentation might tell you placing those annotations on the field variables is ok,,, its a bad idea as a standard. field level requires hibernate to create a proxy before the field can be access in the case of lazy fetches. so just get use to doing it correctly and you wont have the misfortune of finding issues. move all those annotations to the getters as property level access doesnt require the proxy.
field level variables should be private.
you are casting an Integer to an Integer in there... some of that stuff makes me not want to look at it and truthfully will probably be a silly bit of laziness that ends up being your problem.
while you are at it go ahead an initialize the set with new HashSet(0); Things like that. Still broken update us.

Categories

Resources