Get primary key instead the whole object in OneToMany relationship - java

I have the following classes:
#Entity
#Table(name = "elements")
#Inheritance(strategy=InheritanceType.JOINED)
#XmlRootElement
public abstract class Elements implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idelement")
private Integer idElement;
#Basic(optional = false)
#Column(name = "code")
private String code;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "idElement")
#Fetch(value = FetchMode.SUBSELECT)
private Collection<Alarms> alarmsCollection;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "idElement")
#Fetch(value = FetchMode.SUBSELECT)
private Collection<ElementsHistorical> elementsHistoricalCollection;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, mappedBy = "elementsCollection")
#Fetch(value = FetchMode.SUBSELECT)
private Collection<ElementsGroups> elementsGroupsCollection;
//Constructors, getters and setters
}
#Entity
#Table(name = "alarms")
#XmlRootElement(name = "Alarms")
public class Alarms implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idalarm")
private Integer idAlarm;
#JoinColumn(name = "idelement", referencedColumnName = "idelement")
#ManyToOne(optional = false)
private Elements idElement;
//Constructors, getters and setters
}
I created a jersey webservice and a DAO class with CRUD operations to treat Alarms data. With this implementation, when I call GET method, I get the whole Elements object inside the Alarms one. This is the DAO method called:
public List<Alarms> getAlarms(){
Session session = SessionUtil.getSession();
Query query = session.createQuery("from Alarms");
List<Alarms> alarms = query.list();
session.close();
return alarms;
}
I don't want this fetch = FetchType.EAGER fetch type, as I just need the PK of Elements, but after some research this is the only way I found to make my service work.
I tried this and this approach, but I've not been able to make it work.

You can use left outer join fetch in you query.
Query query = session.createQuery("from Alarms alarm left outer join fetch alarm.idElement element");
Now you can keep fetch = FetchType.LAZY (which is default).

Try to add #XmlTransient annotation to fields in Elements class that you want to ignore.
like this :
#Entity
#Table(name = "elements")
#Inheritance(strategy=InheritanceType.JOINED)
#XmlRootElement
public abstract class Elements implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idelement")
private Integer idElement;
#Basic(optional = false)
#Column(name = "code")
#XmlTransient
private String code;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "idElement")
#Fetch(value = FetchMode.SUBSELECT)
#XmlTransient
private Collection<Alarms> alarmsCollection;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "idElement")
#Fetch(value = FetchMode.SUBSELECT)
#XmlTransient
private Collection<ElementsHistorical> elementsHistoricalCollection;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, mappedBy = "elementsCollection")
#Fetch(value = FetchMode.SUBSELECT)
#XmlTransient
private Collection<ElementsGroups> elementsGroupsCollection;
//Constructors, getters and setters
}

You can use multiselect with Tuple, for select only specific columns.
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<Alarms> root = cq.from(Alarms.class);
CollectionJoin<Object, Object> joinCollection = root.joinCollection("alarmsCollection");
cq.multiselect(joinCollection.get("idElement"));
List<Tuple> tupleResult = entityManager.createQuery(cq).getResultList();
for (Tuple t : tupleResult) {
Long idElement = (Long) t.get(0);
}

Related

Hibernate JPA #OneToMany join on 2 columns with OR statement in Entity

I have the following class:
public class Nomenclature extends BaseEntity {
#Id
#Column(name = "NOMENCLATURE_CODE")
private String nomenclatureCode;
#OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL}, mappedBy = "nomenclatureCode", orphanRemoval = true)
private List<Cumul> cumuls = new ArrayList<>();
}
I want to join the following Cumul class on 2 columns WHERE cumul.nomenclatureCode = nomenclature.nomenclatureCode OR cumul.nomenclatureCodeAllowedCumul = nomenclature.nomenclatureCode
public class Cumul extends BaseEntity {
#Id
#Column(columnDefinition = "NUMERIC")
#GeneratedValue(generator = "CUMUL", strategy = GenerationType.SEQUENCE)
private Long id;
#Column(name = "NOMENCLATURE_CODE")
private String nomenclatureCode;
#Column(name = "NOMENCLATURE_CODE_ALLOWED_CUMUL")
private String nomenclatureCodeAllowedCumul;
#OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL},orphanRemoval = true)
#JoinColumns(
{
#JoinColumn(name = "nomenclature_code", referencedColumnName = "nomenclature_code"),
#JoinColumn(name = "nomenclature_code_allowed_cumul", referencedColumnName = "nomenclature_code")
})
private List<Cumul> cumuls = new ArrayList<>();
Worked but this an AND statement not an OR what I was looking for

Hibernate OneToMany mapping & Query generation : More than one row with the given identifier was found

I am using spring-boot-starter-data-jpa 1.5.1.RELEASE which internally uses hibernate-core 5.0.11.Final
My entity looks like this:
AreaDto
#Entity
#Table(name = "AREA")
#EntityListeners(AuditingEntityListener.class)
public class AreaDto {
#Id
#Column(name = "AREA_ROWID")
private String areaRowId;
#OneToMany(cascade = CascadeType.DETACH)
#JoinColumn(name = "AREA_ROWID")
private Collection<FestivalDto> festival;
#OneToMany(cascade = CascadeType.DETACH, mappedBy = "area")
private Collection<ActionDto> actions;
#OneToMany(fetch = FetchType.LAZY)
#JoinTable(name = "FESTIVAL", joinColumns = {
#JoinColumn(name = "AREA_ROWID", referencedColumnName = "AREA_ROWID")}, inverseJoinColumns = {
#JoinColumn(name = "FESTIVAL_ROWID", referencedColumnName = "FESTIVAL_ROWID")})
private Collection<ActionDto> festivalActions;
}
FestivalDto
#Entity
#EntityListeners(AuditingEntityListener.class)
#Table(name = "FESTIVAL")
public class FestivalDto {
#Id
#Column(name = "FESTIVAL_ROWID")
#GeneratedValue(generator = "FESTIVAL_ROWID_SEQ")
private Long festivalRowId;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = true)
#JoinColumn(name = "AREA_ROWID")
private AreaDto area;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "festival")
private Collection<ActionDto> actions = Lists.newArrayList();
}
ActionDto
#Entity
#EntityListeners(AuditingEntityListener.class)
#Table(name = "ACTION")
public class ActionDto implements Serializable {
...
#Id
#Column(name = "ACTION_ID")
#GeneratedValue(generator = "ACTION_ID_SEQ")
private Long actionId;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne(cascade = DETACH, fetch = FetchType.LAZY)
#JoinColumn(name = "FESTIVAL_ROWID")
private FestivalDto festival;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne(cascade = DETACH, fetch = FetchType.LAZY)
#JoinColumn(name = "AREA_ROWID")
private AreaDto area;
}
I'm trying to make sense of the below ideas:
What is the strategy used by hibernate to decide on the festival_rowid (or festival_row ids) used to get all the associated action? How will hibernate generated SQL query vary if i change festivalActions fetch strategies between LAZY and EAGER? I know about proxying, collection proxying and all, my question is specific to how those sql is generated and how it may have an impact on deciding the value of bind parameter.
Is my mapping accurate or should I be using a multimap for this relationship since an area could have multiple festival and each festival could have multiple actions
Background:
I am getting below error which goes away if I change the fetch type from LAZY to EAGER. Hoping to understand the behaviour for gaining some confidence in the fix. I have read SO and error
org.hibernate.HibernateException: More than one row with the given identifier was found: data.dto.ActionDto#280856b5
This mapping does not make much sense. You can't map festivalActions this way because there is no way to persist the state properly through such a mapping. Also festival in AreaDto should be mapped by the area in FestivalDto. Try the following instead:
#Entity
#Table(name = "AREA")
#EntityListeners(AuditingEntityListener.class)
public class AreaDto {
#Id
#Column(name = "AREA_ROWID")
private String areaRowId;
#OneToMany(cascade = CascadeType.DETACH, mappedBy = "area")
private Collection<FestivalDto> festival;
#OneToMany(cascade = CascadeType.DETACH, mappedBy = "area")
private Collection<ActionDto> actions;
public Collection<ActionDto> getFestivalActions() {
return festival.stream().flatMap(f -> f.actions.stream()).collect(Collectors.toList());
}
}
#Entity
#EntityListeners(AuditingEntityListener.class)
#Table(name = "FESTIVAL")
public class FestivalDto {
#Id
#Column(name = "FESTIVAL_ROWID")
#GeneratedValue(generator = "FESTIVAL_ROWID_SEQ")
private Long festivalRowId;
#ManyToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY, optional = true)
#JoinColumn(name = "AREA_ROWID")
private AreaDto area;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "festival")
private Collection<ActionDto> actions = Lists.newArrayList();
}
#Entity
#EntityListeners(AuditingEntityListener.class)
#Table(name = "ACTION")
public class ActionDto implements Serializable {
...
#Id
#Column(name = "ACTION_ID")
#GeneratedValue(generator = "ACTION_ID_SEQ")
private Long actionId;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne(cascade = DETACH, fetch = FetchType.LAZY)
#JoinColumn(name = "FESTIVAL_ROWID")
private FestivalDto festival;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne(cascade = DETACH, fetch = FetchType.LAZY)
#JoinColumn(name = "AREA_ROWID")
private AreaDto area;
}

Why JpaRpository.delete(entity) don't actually delete the entity?

I have this entity
#Builder
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
#Data
#Entity
#Table(name = "visits")
public class Visit {
#EqualsAndHashCode.Include
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#NotNull
#Column(nullable = false, updatable = false)
private long id;
#Column
private LocalDate date;
#Column
private LocalTime startTime;
#Column
private LocalTime endTime;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "client_id")
private Client client;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "employee_id")
private Employee employee;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(
name = "services_booked",
joinColumns = {#JoinColumn(name = "visit_id")},
inverseJoinColumns = {#JoinColumn(name = "service_id")}
)
private Set<Service> servicesBooked = new HashSet<>();
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "visit")
private Set<TimeSlot> timeSlots = new HashSet<>();
}
My controller performs delete action on service bean into transaction:
#Transactional
#DeleteMapping("/{id}")
public ResponseEntity<DeleteVisitResponse> deleteVisit(#PathVariable("id") long visitId,
#RequestAttribute(USER_AUTH) UserAuthDto userAuthDto) {
// some logic
Optional<Visit> visit = visitService.findVisitById(visitId);
// check isPresent via Optional.map
visitService.deleteVisit(visit.get());
// constructing the response
}
And service bean just deletes it:
#Override
public void deleteVisit(#NonNull Visit visit) {
visitRepository.delete(visit);
}
But actually it does not delete it. It performs sequential selects to resolve chained entities. Here are log records of that deletion: https://gist.github.com/bvn13/906582ad39720e033c24ddd6f59f906c
That's all. Why it cannot perform deleting operation?

Hibernate Criteria Api with Inner Join and Many to Many

I'm new with Hibernate and Criteria Query.
How can I implement it with Hibernate Criteria Object?
SELECT stateslocalization.StateId, stateslocalization.localization AS name
FROM processstate
Join states ON states.id = processstate.StateId
JOIN stateslocalization ON stateslocalization.StateId = states.id
WHERE processstate.ProcessId = 38 and processstate.StateId = states.id AND stateslocalization.StateId = states.id
Entities:
Process:
#Entity
#Table(name = "processes")
public class Process {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
#JoinTable(
name = "processstate",
joinColumns = {#JoinColumn(name = "ProcessId")},
inverseJoinColumns = {#JoinColumn(name = "StateId")}
)
private Set<State> states;
//getters and setters.....
}
State:
#Entity
#Table(name = "states")
public class State {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
private String name;
#ManyToMany(mappedBy = "states", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
private Set<Process> processes;
#OneToOne(mappedBy = "state")
private StateLocalization stateLocalization;
//getters and setters.....
}
StateLocalization:
#Entity
#Table(name = "stateslocalization")
public class StateLocalization {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "StateId", referencedColumnName = "id")
private State state;
private String localization;
//getters and setters.....
}
I did it with native query but I don't know how I can implement it to Hibernate Criteria, because I don't have entity processstate (it's only table).

OneToMany PersistentBag

I have a problem with storing OneToMany relationship with Hibernate.
What I got is AdvertisementData entity which looks as follows:
#Entity
#Table(name = "advertisement_data")
public class AdvertisementData {
#Id
#Column(name = "order_id", unique = true, nullable = false)
#GeneratedValue(generator = "gen")
#GenericGenerator(name = "gen", strategy = "foreign", parameters = #Parameter(name = "property", value = "order"))
private Long id;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.MERGE, mappedBy = "advertisementData")
private List<KRPData> krpData;
//setters and getters
}
and KRPData which is defined as follows:
#Entity
public class KRPData {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String description;
#Type(type = "org.hibernate.type.SerializableToBlobType")
private List<String> images;
private String section;
#Type(type = "org.hibernate.type.SerializableToBlobType")
private List<String> filenames;
#ManyToOne
private AdvertisementData advertisementData;
//getters and setters
}
I can see that both entities are stored, however every time I fetch AdvertisementData, the results looks like:
KRPData is returned as PersistentBag without any data.
Hibernate version: 4.2.2.Final
Any ideas what could be the case?
Thank You in advance!

Categories

Resources