Spring Data JPA Non-key field references in Spring Data JPA - java

EntityDiagram How to Event(id) refererences to CurriculumVitae(event_id) and FamilyMember(id) refererences to CurriculumVitae(family_member_id)
My code is :
#Getter
#Setter
#ToString
#Data
#Entity
#Table(name = "CurriculumVitaes")
public class CurriculumVitae implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "identity_card_number")
private String identityCardNumber;
#Column(name = "place_for_identity_cards")
private String placeForIdentityCards;
#Column(name = "phone_number")
private String phoneNumber;
#Column(name = "ethnic")
private String ethnic;
#Column(name = "religion")
private String religion;
#Column(name = "family_composition_after_land_reform")
private String familyCompositionAfterLandReform;
#Column(name = "family_member")
private String familyMember;
#Column(name = "education_level")
private String educationLevel;
#Column(name = "language")
private String language;
#Column(name = "qualification")
private String qualification;
#Column(name = "type_of_education")
private String typeOfEducation;
#Column(name = "specialized_training")
private String specializedTraining;
#Column(name = "health_situation")
private String healthSituation;
#Column(name = "tall")
private String tall;
#Column(name = "weight")
private String weight;
#Column(name = "occupation_or_qualification")
private String occupationOrQualification;
#Column(name = "ranks")
private String rank;
#Column(name = "current_salary")
private String currentSalary;
#Column(name = "date_of_enlistment")
private Date dateOfEnlistment;
#Column(name = "date_of_demobilization")
private Date dateOfDemobilization;
#Column(name = "reason")
private String reason;
#OneToMany(mappedBy = "curriculumVitae", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<Event> event;
#OneToMany(mappedBy = "curriculumVitae", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#ToString.Exclude
#JsonIgnore
private Collection<FamilyMember> familyMemberList;
}
But FamilyMembers(curriculum_vitae_id) references to CurriculumVitae(id)*
#Getter
#Setter
#ToString
#Data
#Entity
#Table(name = "FamilyMembers")
public class FamilyMember implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name")
private String name;
#Column(name = "occupation")
private String occupation;
#Column(name = "august_revolution")
private String augustRevolution;
#Column(name = "resistance_war_against_French_colonialism")
private String resistanceWarAgainstFrenchColonialism;
#Column(name = "activities_from_1955")
private String activitiesFrom1955;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "curriculum_vitae_id", referencedColumnName = "family_member_id")
#EqualsAndHashCode.Exclude
#ToString.Exclude
private CurriculumVitae curriculumVitae;
}

Related

Reading nested collection QueryDSL

I am using queryDSL to fetch the inner collection of data and failed to do so. My entities are
#Entity
#Table(name = "countries")
#Setter
#Getter
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long countryId;
#Column(name = "name")
private String name;
#Column(name = "data")
private String data;
#OneToOne(mappedBy = "country")
private State stateJoin;
}
#Entity
#Table(name = "states")
#Setter
#Getter
public class State {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long stateId;
#Column(name = "name")
private String name;
#Column(name = "count")
private String count;
#Column(name = "co_id")
private Long countryId;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "co_id", referencedColumnName = "id", updatable = false, insertable = false)
private Country country;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "state_id", referencedColumnName = "id")
private Set<Town> towns;
}
#Entity
#Table(name = "towns")
#Setter
#Getter
public class Town {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "town_id")
private Long townId;
#Column(name = "name")
private String name;
#Column(name = "people_count")
private String peopleCount;
#Column(name = "st_id")
private Long stateId;
}
and in querydsl i am trying below query and always failing to retrieve inner collection towns
List<Expression> childGroup = new ArrayList<>();
query.from(countries);
childGroup.addAll(Arrays.asList(countries.name, countries.data, countries.stateJoin));
query.join(countries.stateJoin, State);
childGroup.add(Projections.bean(State.class, name, count, town)
.as((Path) countries.stateJoin));
OR
childGroup.add(Projections.bean(State.class, name, count, list(town)).as((Path) countries.stateJoin));
query.select(fields);
query.where();
final Map<? extends Number, ? extends Object> t =
(Map<? extends Number, ? extends Object>)
query
.limit(pageRequest.getPageSize())
.offset(pageRequest.getOffset())
.distinct()
.transform(
GroupBy.groupBy(groupByPath)
.as(Projections.bean(Countris.class, childGroup.toArray(new Expression[0]))));
while executing the above line exactly i am getting always SQLSyntax error as i see the underlying SQL is with
. as towns
Can some one help me how to read the nested collection formed by JPA join?

Update User Details api returns TransientPropertyValueException:

I'm setting an API endpoint that updates an existing user detail, to do that I try to fetch an existing user from the database by id, when I start the application and test with postman it runs the query on my console but displays TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing and fails to make the intended updates. Here is my code
Member
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name ="member",
indexes = {
#Index(
columnList = "email_address",
name = "email_address_idx",
unique = true
),
},
uniqueConstraints = {
#UniqueConstraint(
columnNames = {"email_address", "phone_number"},
name = "email_address_phone_number_uq"
)
}
)
public class Member {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "nationality_id")
private Country nationality;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "country_of_residence_id")
private Country countryOfResidence;
#Temporal(TemporalType.DATE)
#Column(name ="date_of_birth")
private Date dateOfBirth = new Date();
#Column(name ="current_job_title")
private String currentJobTitle;
#Column(name = "email_address", nullable = false)
private String emailAddress;
#Column(name = "username")
private String username;
#Column(name ="phone_number")
private String phoneNumber;
#Column(name ="city")
private String city;
#Column(name ="state")
private String state;
#Column(name ="password", nullable = false)
private String password;
#Column(name ="avatar")
private String avatar;
#Column(name ="active", nullable = false)
private Boolean active = true;
#CreationTimestamp
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created_on", updatable = false, nullable = false)
private Date createdOn;
#UpdateTimestamp
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "updated_on", nullable = false)
private Date updatedOn;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(
name = "member_roles",
joinColumns = #JoinColumn(
name = "member_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(
name = "role_id", referencedColumnName = "id")
)
private Set<Role> roles = new HashSet<>();
public void addRole(Role role) {
this.getRoles().add(role);
}
public void clearRoles() {
this.roles = new HashSet<>();
}
}
MemberDto
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public class UpdateMemberDto {
#NotNull(message = "{member.first_name.notNull}")
private String firstName;
#NotNull(message = "{member.last_name.notNull}")
private String lastName;
private Date dateOfBirth;
private String currentJobTitle;
#NotNull(message = "{member.email_address.notNull}")
private String emailAddress;
private String username;
#NotNull(message = "{member.phone_number.notNull}")
private String phoneNumber;
private String city;
private String state;
private String password;
private String avatar;
private Boolean active;
}
ServiceImpl
#Slf4j
#Service
public class UpdateMemberServiceImpl implements UpdateMemberService {
#Autowired
private ModelMapper modelMapper;
private final UpdateMemberRepository repository;
private final MemberJpaRepository jpaRepository;
public UpdateMemberServiceImpl(UpdateMemberRepository repository, MemberJpaRepository jpaRepository) {
this.repository = repository;
this.jpaRepository = jpaRepository;
}
#Override
#Transactional
public Member update(Long id, UpdateMemberDto body) {
Optional<Member> existingMember = jpaRepository.findById(id);
if (existingMember != null) {
Member member = new Member();
member = modelMapper.map(body, Member.class);
member.setId(id);
member = jpaRepository.save(member);
return member;
}
throw new MemberNotFoundException(id);
}
}

Empty List between ManyToMany relationship

I have two entities,Client and Product ,and they have a relation #ManyToMany, when I do a POST to create a Client with a Product, I recive a empty list of Produtcs.
public class Produto implements Serializable {
private static final long serialVersionUID = -6381222920639794489L;
#Id
#Column(name = "id", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "descricao")
private String descricao;
#Column(name = "preco")
private Float preco;
#ManyToMany
#JoinTable(name = "produto_cliente",
joinColumns = #JoinColumn(name = "cliente_fk"),
inverseJoinColumns = #JoinColumn(name = "produto_fk"))
private List<Cliente> clientId;
}
public class Cliente implements Serializable {
private static final long serialVersionUID = -1195126015856369746L;
#Id
#Column(name = "id", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "nome")
private String nome;
#Column(name = "cpf")
private String cpf;
#ManyToMany(mappedBy = "clientId")
private List<Produto> produtos;
}
The list of products
The list os clients after I created and added the product

delete call stuck for forever in a Many to One Relationship

Trying to run a delete query on a many-one relationship. But sometime it's stuck for a while when the count of row delete is more then ~50.
Repository:
#Repository
public interface TransitItemRepository extends JpaRepository<TransitItemsMapping, UUID> {
#Modifying
#Transactional
#Query(value="delete from TransitItemsMapping t where t.grouping_form_id=:groupingFormId",nativeQuery = true)
void deleteByGroupingFormId(#Param("groupingFormId") UUID groupingFormId);
}
Domain:TransitItemsMapping.java
#Data
#Entity
#Table(name = "TransitItemsMapping")
public class TransitItemsMapping implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GenericGenerator(name = "uuid", strategy = "uuid2")
#GeneratedValue(generator = "uuid")
#Column(name = "transit_Item_id",unique = true, nullable = false)
private UUID transitItemId;
#ToString.Exclude
#JsonManagedReference
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "grouping_form_id")
//#OnDelete(action = OnDeleteAction.CASCADE)
private GroupingForm groupingForm;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(referencedColumnName = "dim_Item_ID",name = "item_id")
private Item item;
#Column(name ="item_relationship_id", insertable = false,updatable = false)
private String itemRelationshipId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "item_relationship_id",referencedColumnName = "dim_item_relationship_id")
private VendorFactoryItem vendorFactoryItem;
#Column(name = "edam_id")
private String edamId;
#Column(name = "model_number")
private String modelNumber;
#Column(name = "description")
private String description;
#Column(name = "packaging_details")
private String packagingDetails;
#Column(name = "packaging_method")
private String packagingMethod;
#Column(name = "is_side_stack")
private String isSideStack;
#Column(name = "quantity")
private Integer quantity;
#Column(name = "dimensions")
private String dimensions;
#Column(name = "product_net_weight")
private String productNetWeight;
#Column(name = "plastic_bag_ind")
private String plasticBagInd;
#Column(name = "insertion_order")
private Integer insertionOrder;
#Column(name = "comments")
private String comments;
#Column(name = "item_unique_id")
private String itemUniqueId;
#Column(name = "itm_pak_qty")
private Integer itemPackQuantity;
}
GroupingForm.java
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode
#Entity
#Table(name = "GroupingForm")
public class GroupingForm implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GenericGenerator(name = "uuid", strategy = "uuid2")
#GeneratedValue(generator = "uuid")
#Column(name = "grouping_form_id",unique = true, nullable = false)
private UUID groupingFormId;
#Column(name = "grouping_form_name")
private String groupingFormName;
#Column(name = "vid")
private String vid;
#Column(name = "vendor_name")
private String vendorName;
#Column(name = "hovbu")
private String hovbu;
#Column(name = "fid")
private String fid;
#Column(name = "factory_name")
private String factoryName;
#Column(name = "item_count")
private Integer itemCount;
#CreationTimestamp
#Column(name = "creation_date")
private Timestamp creationDate;
#Column(name = "created_by")
private String createdBy;
#UpdateTimestamp
#Column(name = "modified_date")
private Timestamp modifiedDate;
#Column(name = "modified_by")
private String modifiedBy;
#Column(name = "product_engineer")
private String productEngineer;
#Column(name = "status")
private String status;
#Column(name = "sourcing_type")
private String sourcingType;
#Column(name = "total_comments")
private Integer totalComments;
#Column(name = "factory_name_chinese")
private String factoryNameChinese;
#Column(name = "grouping_form_type")
private String groupingFormType;//to save as Product/transit/Product_transit
#Column(name = "ref_id")
private String refId;
#JsonBackReference
#OneToMany(mappedBy = "groupingForm", cascade = CascadeType.ALL)
private List<ProductItemsMapping> productItems = new ArrayList<>();
#JsonBackReference
#OneToMany(mappedBy = "groupingForm", cascade = CascadeType.ALL)
private List<TransitItemsMapping> transitItems = new ArrayList<>();
#Column(name = "pdf_status")
private String pdfStatus;
public GroupingForm(UUID groupingFormId,String groupingFormName, String vid, String vendorName, String hovbu,
String fid, String factoryName, String status, String sourcingType, Integer totalComments,
Date creationDate, String createdBy, Date modifiedDate, String modifiedBy, String productEngineer,
Integer itemCount, String groupingFormType, String refId, String factoryNameChinese) {
this.groupingFormId = groupingFormId;
this.groupingFormName = groupingFormName;
this.vid = vid;
this.vendorName = vendorName;
this.hovbu = hovbu;
this.fid = fid;
this.factoryName = factoryName;
this.status = status;
this.sourcingType = sourcingType;
this.totalComments = totalComments;
this.creationDate = creationDate!=null?new Timestamp(creationDate.getTime()):null;
this.createdBy = createdBy;
this.modifiedDate = modifiedDate!=null?new Timestamp(modifiedDate.getTime()):null;
this.modifiedBy = modifiedBy;
this.productEngineer = productEngineer;
this.itemCount = itemCount;
this.groupingFormType = groupingFormType;
this.refId = refId;
this.factoryNameChinese = factoryNameChinese;
}
}
Service: methods which already annotated with #Transactional
private void updateTransitItem(GroupingCardsDto groupingCardsDto, GroupingForm groupingForm) {
transitItemRepository.deleteByGroupingFormId(groupingCardsDto.getGroupingFormDto().getGroupingFormId());
groupingFormService.saveTransitItems(groupingCardsDto.getGroupingFormDto(), groupingForm);
}
when I am running eclipse in debug mode then my breakpoint is stuck in delete method. I am using
PostgreSQL 9.6.24 on x86_64-pc-linux-gnu, compiled by Debian clang version 12.0.1, 64-bit
version, and for pool connection Hikari-CP-3.2.0.
And If I let my debug running after long time (~45min) I am getting below error.
marked as broken because of SQLSTATE(08006), ErrorCode(0)\norg.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.
Thanks in advance.
There are two possible reasons for this.
Either your delete statement actually takes a really long time, or it is stuck on a lock.
45 min, is certainly a lot for simple delete and could only be expected when you are working on huge amounts of data, like many millions of rows. Use the explain plan to validate that the expected indexes are used.
I consider locks the more likely reason for the problem. You'll need to check what locks are present and where they are coming from. This wiki page about lock monitoring in PostgreSQL seems to be a good starting point.

Some parent entity value cannot be saved to child entity

When i save the job entity i was expecting that the child under job should also reflect in the db. The problem is that the ref_id and revision does not contain any value from the db.
here is the result from mysql db (removed confidential data)
This is my Job entity class
#Entity
#Table(name = "job")
public class Job implements Serializable {
private static final long serialVersionUID = -2075866246194059832L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "ref_id")
private String refId;
#Column(name = "revision")
private int revision;
#Column(name = "appname")
private String appName;
#Column(name = "vendor")
private String vendor;
#Column(name = "version")
private String version;
#Column(name = "locale")
private String locale;
#Column(name = "platform")
private String platform;
#Column(name = "tier")
private String tier;
#Column(name = "category")
private String category;
#Column(name = "functional_tag")
private String functional;
#Column(name = "job_start_date")
private Date jobStartDate;
#Column(name = "author")
private String author;
#Enumerated(EnumType.STRING)
private Status status;
#Column(name = "release_version")
private String releaseVersion;
#OneToMany(mappedBy = "job", cascade = CascadeType.PERSIST)
private List<Task> tasks;
}
And here is the child
#Entity
#Table(name = "task")
public class Task implements Serializable {
private static final long serialVersionUID = -7395753611385528546L;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "module_name")
private String moduleName;
#Column(name = "start_time")
private Date startTime;
#Column(name = "end_time")
private Date endTime;
#Enumerated(EnumType.STRING)
private Status status;
#Column(name = "machine_ip")
private String machineIp;
#Column(name = "data_center")
private String dataCenter;
#Column(name = "description")
private String description;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinColumns({#JoinColumn(name = "ref_id", referencedColumnName = "ref_id"),
#JoinColumn(name = "revision", referencedColumnName = "revision")})
private Job job;
}
Here is the code that persist the entity
#Service
public class QReaderService {
#Autowired
private JobRepository jobRepository;
#Autowired
private TaskRepository taskRepository;
public boolean addJob(Job job) {
Job previousJob = jobRepository.findByJobRefId(job.getRefId());
if (previousJob == null) {
**jobRepository.save(job);**
return true;
} else {
switch (job.getStatus()) {
case FAILED:
case EXCEPTION:
int revision = 0;
revision += previousJob.getRevision();
previousJob.setStatus(Status.FAILED);
jobRepository.save(previousJob);
break;
}
}
return true;
}
}
This is how i build the job entity
Job job = new Job();
job.setRefId("f78d9as7f98dsa7f97a97f98sda9f7");
job.setAppName("appname");
job.setLocale("locale");
job.setPlatform("platform");
job.setCategory("category");
job.setReleaseVersion("1.1");
job.setStatus(Status.PROCESSING);
job.setAuthor("author");
job.setFunctional("functional");
job.setJobStartDate(new Date());
job.setVersion("1.1");
job.setTier("tier1");
job.setVendor("vendor");
Task task = new Task();
task.setDescription("description");
task.setDataCenter("dataCenter");
task.setStartTime(new Date());
task.setStatus(Status.PROCESSING);
task.setMachineIp("ip");
task.setModuleName("module");
job.setTasks(new ArrayList<Task>(Arrays.asList(task)));
jobRepository.save(job);
To persist child entities when you call save on parent entity, both sides of the relations should be set.
job.setTasks(job.setTasks(new ArrayList<Task>(Arrays.asList(task)));
//Missing line //Important for persistence of child
task.setJob(job);
Hope this helps.

Categories