How to map bidirectional #OneToMany and #OneToOne on the same entity - java

I have two enteties and I want to be able access one of them from another and vise versa (bidirectional). But sometimes when persisting an order as stopLossOrder it's not saved to position. If you have any ideas of how it can be implemented (if it's possible this way or similar) I would be glad to hear.
Later on I want to add more orders to position entity similarly to 'stopLossOrder'
#Entity(name = "Position")
#Table(name = "positions")
#Getter #Setter
public class PositionEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
orphanRemoval = true)
#JoinColumn(name = "stop_loss_order_id", referencedColumnName = "id")
private OrderEntity stopLossOrder;
#OneToMany(mappedBy = "position",
cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
orphanRemoval = true)
private Set<OrderEntity> orders = new HashSet<>();
public void setStopLossOrder(OrderEntity stopLossOrder) {
this.stopLossOrder = stopLossOrder;
stopLossOrder.setPosition(this);
}
public boolean addOrder(OrderEntity orderEntity) {
orderEntity.setPosition(this);
return orders.add(orderEntity);
}
}
#Entity(name = "Order")
#Table(name = "orders")
#Getter
#Setter
public class OrderEntity implements Serializable {
#Getter(AccessLevel.NONE)
#Setter(AccessLevel.NONE)
private static final long serialVersionUID = -1462587657644552577L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(optional = false)
private PositionEntity position;
}
Persisting:
if (orderEntity.getType() == OrderType.STOP_MARKET) {
positionEntity.setStopLossOrder(orderEntity);
} else {
boolean isAdded = positionEntity.addOrder(orderEntity);
if (!isAdded)
throw new TradeServiceException("Order with id: " + order.getOrderId() + " already added to position.");
}
orderEntity = orderRepository.save(orderEntity);

Related

Hibernate LazyInitializationException

I am trying to get the versions field within my MachineGroup Entity that is ManyToMany relationship. I am trying to fetch it in a custom serializer using ObjectMapper but for some reason I always get the LazyInitializationException - org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.altair.autoTester.entities.machinegroup.MachineGroup.versions, could not initialize proxy - no Session.
MachineGroup
#Entity
#Table(name="machine_groups")
#Getter
#Setter
#AllArgsConstructor(access = AccessLevel.PUBLIC)
#NoArgsConstructor
public class MachineGroup {
#Id
#GeneratedValue(strategy= GenerationType.AUTO, generator = "machine_groups_seq")
#SequenceGenerator(name = "machine_groups_seq", allocationSize = 1, initialValue = 2)
#Column(name = "id")
private long id;
#ManyToMany(cascade = CascadeType.MERGE)
#JoinTable(name = "machine_groups_to_versions",
joinColumns = #JoinColumn(name = "machine_group_id"),
inverseJoinColumns = #JoinColumn(name = "version_id"))
#JsonManagedReference(value="machineGroups-versions")
private Set<Version> versions = new HashSet<>();
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "machine_groups_to_tr_types",
joinColumns = #JoinColumn(name = "machine_group_id"),
inverseJoinColumns = #JoinColumn(name = "tr_type_id"))
private Set<TrType> trTypes = new HashSet<>();
}
Version.java
#Entity
#Table(name="versions")
#Getter
#Setter
public class Version {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "versions_seq")
#SequenceGenerator(name = "versions_seq", allocationSize = 1)
#Column(name = "id")
private long id;
#Column(name = "name", unique = true)
private String name;
#Column(name = "creation_time")
private Date creationTime;
#Column(name = "exe_file")
#Lob
private Blob exeFile;
#JsonBackReference(value="machineGroups-versions")
#ManyToMany(mappedBy = "versions", cascade = CascadeType.MERGE)
private Set<MachineGroup> machineGroups = new HashSet<>();
public Version(){};
public Version(String name) {
this.name = name;
}
}
MachineGroupSerializer.java
public class MachineGroupSerializer extends StdSerializer<MachineGroup> {
public MachineGroupSerializer() {
this(null);
}
public MachineGroupSerializer(Class<MachineGroup> t) {
super(t);
}
#Transactional
#Override
public void serialize(MachineGroup machineGroup,
JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeNumberField("id",machineGroup.getId());
jsonGenerator.writeObjectField("versions", machineGroup.getVersions().stream().map(Version::getId).collect(Collectors.toSet()));
jsonGenerator.writeObjectField("trTypes", machineGroup.getTrTypes().stream().map(TrType::getId).collect(Collectors.toSet()));
jsonGenerator.writeEndObject();
}
}
TrTypes.java
#Table(name = "tr_types", indexes = {
#Index(name = "tr_types_type_name_uindex", columnList = "type_name", unique = true)
})
#Entity
#AllArgsConstructor(access = AccessLevel.PUBLIC)
#NoArgsConstructor
public class TrType {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "type_name", nullable = false)
private String typeName;
}
I put the JsonManagedReference and JsonBackReference so I won't have infinite loop calling one another, not sure if it's causing any issues.
Calling the getTrTypes() function works but has the EAGER fetchType which I do not want to add to the versions collection.
What can cause this lazy exception to occur and how can I prevent it?
Also the function calling the serialzier within my MachineGroupService has the #Transactional annotation, I saw something that is related to the hibernate session that might be close at the serializer level.

Hibernate joining tables with multiple primary keys

I have figured out how to join 2 tables with single primary key. But now I need to join 4 tables and some of these table with composite primary keys.
Here is my table picture
And I want to join them, so I generate classes for them:
// Record
#Getter
#Setter
#ToString
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "record")
public class Record implements java.io.Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name = "student_id")
private Integer studentId;
#Id
#Column(name = "exam_id")
private Integer examId;
#Column(name = "total_score")
private Integer totalScore;
#Column(name = "student_score")
private Integer studentScore;
#Column(name = "submission_id")
private Integer submissionId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "student_id")
private Student student;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "submission_id")
private Submission submission;
}
// Submission
#Getter
#Setter
#ToString
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "submission")
public class Submission implements java.io.Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name = "submission_id")
private Integer submissionId;
#Id
#Column(name = "question_id")
private Integer questionId;
#Column(name = "stu_answer")
private String stuAnswer;
#OneToOne(fetch = FetchType.LAZY, mappedBy = "submission")
private Record record;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "submission")
private Set<Question> question;
}
// Question
#Getter
#Setter
#ToString
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "question")
public class Question implements java.io.Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "question_id")
private Integer questionId;
#Column(name = "content")
private String content;
#Column(name = "score")
private Integer score;
#Column(name = "is_delete")
private Integer isDelete;
#Column(name = "option_id")
private Integer optionId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "submission_id")
private Submission submission;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "optional_id")
private Optional optional;
}
// Optional
#Getter
#Setter
#ToString
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "optional")
public class Optional implements java.io.Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "option_id")
private Integer optionId;
#Column(name = "content")
private String content;
#Column(name = "is_delete")
private Integer isDelete;
#Column(name = "answer")
private String answer;
#OneToOne(fetch = FetchType.LAZY, mappedBy = "optional")
private Question question;
}
// Final class to store information
public class RcdSubQuesOpt {
private Integer studentId;
private Integer examId;
private Integer questionId;
private String stuAnswer;
private String qContent;
private String oContent;
private String answer;
}
And this is code for JPA
#Override
public List<RcdSubQuesOpt> getRcdSubQuesOpt(int studentID, int examId) {
Session session = this.getSession();
List<RcdSubQuesOpt> results;
Transaction transaction = null;
try {
transaction = session.beginTransaction();
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<RcdSubQuesOpt> criteriaQuery = criteriaBuilder.createQuery(RcdSubQuesOpt.class);
// Try to join tables
Root<Record> pRoot = criteriaQuery.from(Record.class);
pRoot.join("submission", JoinType.INNER);
pRoot.join("question", JoinType.INNER);
pRoot.join("optional", JoinType.INNER);
criteriaQuery.multiselect(
pRoot.get(columns in RcdSubQuesOpt Class......));
// Try to add constraints
Predicate predicate = pRoot.get("examId").in(Arrays.asList(1));
criteriaQuery.where(predicate);
// try to do queries
results = session.createQuery(criteriaQuery).getResultList();
transaction.commit();
} catch (Exception e) {
results = null;
if (transaction != null) {
transaction.rollback();
}
} finally {
session.close();
}
return results;
}
But hibernate throw error as following:
Enitial SessionFactory creation failedA Foreign key refering com.domain.Submission from com.domain.Record has the wrong number of column. should be 2
Exception in thread "main" java.lang.ExceptionInInitializerError
I think it's the composite primary keys problem. But solution I searched is not suitable to solve it. Anyone give me some advice? Thanks!
To reference a composite primary key, you need to use #JoinColumns (plural).
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "sub_submission_id", referencedColumnName = "submission_id"),
#JoinColumn(name = "sub_question_id", referencedColumnName = "question_id")
})
private Submission submission;
However, I must admit, I don't understand your model - especially why Submission has a composite PK with question_id. It looks that one Submission has many Questions, why to include question_id as part of Submission PK?
Perhaps, I'm missing something, because the diagram is not fully visible.

Spring Data JPA child entity missing parent ID after transitive save

I have the following class structure
#Entity
#Data // lombok
public class Entity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "entity_details_id", referencedColumnName = "id")
#JsonManagedReference(value = "entityDetails")
private EntityDetails entityDetails;
}
#Entity
#Data
public class EntityDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(mappedBy = "entityDetails")
#JsonBackReference(value = "entityDetails")
private Entity entity;
// Some more fields
#OneToMany(mappedBy = "entityDetails", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonManagedReference(value = "childEntityDetails")
private List<Child> childList;
}
#Entity
#Data
public class Child {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "description")
private String description;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "entity_details_id")
#JsonBackReference(value = "childEntityDetails)
private EntityDetails entityDetails;
}
Assume I have an Entity object with the following structure:
Entity{
id: null,
entityDetails: {
id: null,
childList: [
{ id: null, description: "ch1" },
{ id: null, description: "ch2" }
]
}
}
When I call entityRepository.save(entity), all the objects are persisted, but the Child table does not have a value for entity_details_id. The other values are correct (I do have Entity.entity_details_id correctly set), but this one does not work. I'm not sure if I'm missing something or if I'm just doing it wrong.

How to copy JPA entity?

How to copy entity with multiple #OneToMany?
I have entities:
Profile.java
#Getter
#Setter
#ToString
#JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
#EqualsAndHashCode(exclude = {"id"})
#Entity
#Table(name = "profile")
public class Profile implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "profile", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ProfileDoc> documents = new ArrayList<>();
#OneToMany(mappedBy = "profile", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Contact> contacts = new ArrayList<>();
#OneToOne(mappedBy = "profileAddress", cascade = CascadeType.ALL, orphanRemoval = true)
private AddressBirth birthPlace;
}
ProfileDoc
#Getter
#Setter
#JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
#ToString(exclude = "profile")
#EqualsAndHashCode(exclude = {"id", "profile"})
#TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
#Entity
#Table(name = "profile_doc")
public class ProfileDoc implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "doc_code")
private String documentCode;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="profile_id")
private Profile profile;
#OneToMany(mappedBy = "document", cascade = CascadeType.ALL, orphanRemoval = true)
private List<DocFile> files = new ArrayList<>();
}
How to copy Profile(all field) without id?
as I understand it, you need to copy documents without profile_id in ProfileDoc class
UPD:
I want copy entity from another entity(copy) for save to DB
BeanUtils.copyProperties(profile, newProfile);
if I copy with Id, then the original entity will update, not a new one

cascadeType.REMOVE not working(JPA spring data)

Below is my code. I want to delete all the records of tracking_event when i delete tracking table record which are in oneToMany relationship
Tracking entity
#Entity
#Table(name = "TRACKING")
public class Tracking {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "TRACKING_ID")
private int id;
#JsonIgnore
#OneToMany(mappedBy = "tracking",cascade = CascadeType.REMOVE)
private List<TrackingEvent> trackingEvents;
}
TrackingEvent entity
#Entity
#Table(name = "TRACKING_EVENT")
public class TrackingEvent {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "TRACKING_EVENT_ID")
private int id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TRACKING_ID")
private Tracking tracking;
}
TrackingRepository interface
public interface TrackingRepository extends CrudRepository<Tracking, Integer> {
#Modifying
#Transactional
#Query(" DELETE FROM Tracking WHERE id = :tid")
void deleteByUpdatedDate(#Param("tid") int tid);
}
I also tried using
#OneToMany(mappedBy = "tracking",cascade = CascadeType.REMOVE,orphanRemoval = true)
private List<TrackingEvent> trackingEvents;`

Categories

Resources