Criteria query on part of a composite key - java

We recently ran across a bug in our software due to a missing #Id annotation:
#Entity
#Table (name ="PATRONQRSPLANS")
//#IdClass(PatronPlan.class) <-- this was missing
public class Balance {
#Transient
private String kind;
#Transient
private String planName;
#Transient
private PlanCategory planCategory;
#Id
#Column(name="PATRONID")
private int patronId;
//#Id <--- and this was missing
#Column(name="PLANID")
private int planId;
#Column(name="BALANCE")
private int balance;
#Column(name="ENDDATE")
private Date expirationDate;
public Balance() {
this.kind = "balance";
}
public Balance(int balance, int planId, Date expirationDate) {
this.balance = balance;
this.planId = planId;
this.expirationDate = expirationDate;
this.kind = "balance";
}
public int getPatronId() {
return patronId;
}
public void setPatronId(int patronId) {
this.patronId = patronId;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public int getPlanId() {
return planId;
}
public void setPlanId(int planId) {
this.planId = planId;
}
public String getPlanName() {
return planName;
}
public void setPlanName(String planName) {
this.planName = planName;
}
public String getKind() {
return kind;
}
public void setKind(String kind) {
this.kind = kind;
}
public Date getExpirationDate() {
return expirationDate;
}
public void setExpirationDate(Date expirationDate) {
this.expirationDate = expirationDate;
}
public PlanCategory getPlanCategory() {
return planCategory;
}
public void setPlanCategory(PlanCategory planCategory) {
this.planCategory = planCategory;
}
}
The problem is that the table has a primary key constraint on both planId and patronId, so I need a composite key. The query below (without the commented out annotations above), for a patron that has 2 different plans, will return 2 copies of the same plan instead of 2 different ones.
public List<Balance> getBalancesByPatronId(int patronId) {
CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Balance> query = builder.createQuery(Balance.class);
Root<Balance> s = query.from(Balance.class);
query.select(s);
query.where(builder.equal(s.get("patronId"), patronId));
return entityManager.createQuery(query).getResultList();
}
To remedy this, I added an #Id and #IdClass annotation as commented out above, as well as creating this class:
public class PatronPlan implements Serializable {
private static final long serialVersionUID = -3518083815234439123L;
#Id
#Column(name="PATRONID")
private int patronId;
#Id
#Column(name="PLANID")
private int planId;
public int getPatronId() {
return patronId;
}
public void setPatronId(int patronId) {
this.patronId = patronId;
}
public int getPlanId() {
return planId;
}
public void setPlanId(int planId) {
this.planId = planId;
}
#Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (!this.getClass().isAssignableFrom(obj.getClass())) return false;
PatronPlan other = (PatronPlan) obj;
return Objects.equals(patronId, other.getPatronId()) && Objects.equals(planId, other.getPlanId());
}
#Override
public int hashCode() {
return Objects.hash(patronId, planId);
}
}
But now I get a NullPointerException in my critera query on the statement
s.get("patronId"), because patronId is not showing up as a declaredAttribute, though it does seem to be showing up in the id information.
Is my composite key setup correct and how to I query for part of a composite key using the criteria api?
If it wasn't clear above, the goal is to be able to get all the Balance objects with a given patronId, even though patronId is only part of the composite key.

I am not certain if this is correct, but it seems to be working. Is this correct? My knowledge of hibernate is limited.
public List<Balance> getBalancesByPatronId(int patronId) {
CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Balance> query = builder.createQuery(Balance.class);
Metamodel metaModel = getEntityManager().getMetamodel();
SingularAttribute<Balance, Integer> patronIdAttr =
(SingularAttribute<Balance, Integer>) metaModel.entity(Balance.class)
.getIdClassAttributes().toArray()[0];
Root<Balance> s = query.from(Balance.class);
query.select(s);
query.where(builder.equal(s.get(patronIdAttr), patronId));
return entityManager.createQuery(query).getResultList();
}

Related

Spring Data Neo4j 4.2 query for labels or node id always return null

Currently, I'm building a graph visualization app using Spring Boot & Neo4j. But when I call a method from my entity Neo4jRepository to get NodeEntity labels, it always returns a null value. Is the problem in my node entity?
This is my node entity
#NodeEntity(label="Personnel")
public class PersonnelNode {
private Long id;
#Labels
private Set<String> labels;
#GraphId
private Long personnelId;
private String personnelKey;
private String personnelNameIN;
private Boolean isTeamLeader;
private Boolean isQA;
private Boolean isSuperUser;
private Short companyGroupId;
private Boolean isActive;
private Timestamp created;
private String createdBy;
private Timestamp lastModified;
private String lastModifiedBy;
#Relationship(type="PERSONNEL_TASK", direction=Relationship.OUTGOING)
private TaskNode personnelTasks;
private Long employeeDataId;
public PersonnelNode() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Set<String> getLabels() {
return labels;
}
public void setLabels(Set<String> labels) {
this.labels = labels;
}
public Long getPersonnelId() {
return personnelId;
}
public void setPersonnelId(Long personnelId) {
this.personnelId = personnelId;
}
public String getPersonnelKey() {
return personnelKey;
}
public void setPersonnelKey(String personnelKey) {
this.personnelKey = personnelKey;
}
public String getPersonnelNameIN() {
return personnelNameIN;
}
public void setPersonnelNameIN(String personnelNameIN) {
this.personnelNameIN = personnelNameIN;
}
public Boolean getIsTeamLeader() {
return isTeamLeader;
}
public void setIsTeamLeader(Boolean isTeamLeader) {
this.isTeamLeader = isTeamLeader;
}
public Boolean getIsQA() {
return isQA;
}
public void setIsQA(Boolean isQA) {
this.isQA = isQA;
}
public Boolean getIsSuperUser() {
return isSuperUser;
}
public void setIsSuperUser(Boolean isSuperUser) {
this.isSuperUser = isSuperUser;
}
public Short getCompanyGroupId() {
return companyGroupId;
}
public void setCompanyGroupId(Short companyGroupId) {
this.companyGroupId = companyGroupId;
}
public Boolean getIsActive() {
return isActive;
}
public void setIsActive(Boolean isActive) {
this.isActive = isActive;
}
public Timestamp getCreated() {
return created;
}
public void setCreated(Timestamp created) {
this.created = created;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public Timestamp getLastModified() {
return lastModified;
}
public void setLastModified(Timestamp lastModified) {
this.lastModified = lastModified;
}
public String getLastModifiedBy() {
return lastModifiedBy;
}
public void setLastModifiedBy(String lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}
public Long getEmployeeDataId() {
return employeeDataId;
}
public void setEmployeeDataId(Long employeeDataId) {
this.employeeDataId = employeeDataId;
}
public TaskNode getPersonnelTasks() {
return personnelTasks;
}
public void setPersonnelTasks(TaskNode personnelTasks) {
this.personnelTasks = personnelTasks;
}
}
My Dao Class
#Component
public class PersonnelNodeDao implements IPersonnelNodeDao {
private PersonnelNodeRepository personnelRepository;
#Autowired
public PersonnelNodeDao(PersonnelNodeRepository personnelRepository) {
this.personnelRepository = personnelRepository;
}
#Override
public PersonnelNode getByEmployeeDataId(Long employeeDataId) {
return personnelRepository.findByEmployeeDataId(employeeDataId);
}
#Override
public PersonnelNode getByPersonnelId(Long personnelId) {
return personnelRepository.findByPersonnelId(personnelId);
}
#Override
public Object getLabelsByPersonnelId(Long personnelId) {
return personnelRepository.getLabelsByPersonnelId(personnelId);
}
}
And this is my Neo4jRepository Class
public interface PersonnelNodeRepository extends Neo4jRepository<PersonnelNode, Long> {
#Query(""
+"MATCH (p:Personnel)-[r:PERSONNEL_EMPLOYEE]->(e:Employee) "
+ "WHERE e.employeeDataId = {0} RETURN p")
PersonnelNode findByEmployeeDataId(Long employeeDataId);
#Query("MATCH (p:Personnel) WHERE p.personnelId = {0} RETURN p, ID(p), labels(p)")
PersonnelNode findByPersonnelId(Long personnelId);
#Query(""
+ "MATCH p=(n:Personnel)-[r:PERSONNEL_TASK]->(t:Task {isActive: true}) "
+ "<-[pt:PROJECT_TASK]-(j:Project) "
+ "WHERE n.personnelId= {0} "
+ "RETURN nodes(p) as nodes, rels(p) as relationships")
List<Graph<PersonnelNode>> getPersonnelLoadTaskGraphByEmployeeDataId(Long employeeDataId);
#Query("MATCH (p:Personnel) WHERE p.personnelId = {0} RETURN labels(p)")
Object getLabelsByPersonnelId(Long personnelId);
}
This is my service that calls the method
Object nodePersonnel = personnelNodeDao.getLabelsByPersonnelId(Long.valueOf("2"));
The result is same when i set return variable with my node entity in my service also in my repository, its always return null value
PersonnelNode nodePersonnel = personnelNodeDao.getByPersonnelId(Long.valueOf("2"));
Actually my problem is, just for this entity. For antoher entity i could get the node id and the labels. This is the data return for personnel entity.
Data Retrun From PersonnelRepository
FYI I'm using Spring Data Neo4j 4.2, spring boot 1.5.2 and ogm 2.1. Thank you before.

Spring Data JPA - Get the values of a non-entity column of a custom native query

I am using Spring Boot/MVC.
I have a custom query using JpaRepository:
public interface WorkOrderRepository extends JpaRepository<WorkOrder, Integer> {
#Query(value = "SELECT * FROM (SELECT * FROM workorder) Sub1 INNER JOIN (SELECT wo_number, GROUP_CONCAT(service_type SEPARATOR ', ') AS 'service_types' FROM service_type GROUP BY wo_number) Sub2 ON Sub1.wo_number=Sub2.wo_number WHERE fleet_company_id=?1 AND (order_status='On-Bidding' OR order_status='Draft')", nativeQuery = true)
Collection<WorkOrder> findWorkOrdersByFleet(Long fleetCompanyID);
}
It returns the following table:
http://imgur.com/Ylkc6U0
As you can see it has service_types columns which is a result of Concat, it's not part of the entity class. My problem is how can I get the value of that column. Some said I can use a separate DTO to map the service_types column? Or I can use 'new' keyword? Maybe you have other worked on me. I also tried to make a transient column service_types but it didn't work.
This is my entity class:
#Entity
#Table(name="workorder")
public class WorkOrder {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="wo_number")
private Long woNumber;
#ManyToOne(optional=false, cascade=CascadeType.ALL)
#JoinColumn(name = "vehicle_id")
private Vehicle vehicle;
#ManyToOne(optional=false, cascade=CascadeType.ALL)
#JoinColumn(name = "fleet_company_id")
private FleetCompany fleetCompany;
#Column(name="order_title")
private String orderTitle;
#Column(name="order_date")
private String orderDate;
#Column(name="order_time")
private String orderTime;
#Column(name="order_status")
private String orderStatus;
#Column(name="ref_number")
private String refNumber;
#Column(name="proposals")
private int proposals;
//#Column(name="serviceTypes")
#Transient
private int serviceTypes;
public WorkOrder() {
super();
}
public Long getWoNumber() {
return woNumber;
}
public void setWoNumber(Long woNumber) {
this.woNumber = woNumber;
}
public String getOrderTitle() {
return orderTitle;
}
public void setOrderTitle(String orderTitle) {
this.orderTitle = orderTitle;
}
public String getOrderDate() {
return orderDate;
}
public void setOrderDate(String orderDate) {
this.orderDate = orderDate;
}
public String getOrderTime() {
return orderTime;
}
public void setOrderTime(String orderTime) {
this.orderTime = orderTime;
}
public String getOrderStatus() {
return orderStatus;
}
public void setOrderStatus(String orderStatus) {
this.orderStatus = orderStatus;
}
public String getRefNumber() {
return refNumber;
}
public void setRefNumber(String refNumber) {
this.refNumber = refNumber;
}
public int getProposals() {
return proposals;
}
public void setProposals(int proposals) {
this.proposals = proposals;
}
public Vehicle getVehicle() {
return vehicle;
}
public void setVehicle(Vehicle vehicle) {
this.vehicle = vehicle;
}
public FleetCompany getFleetCompany() {
return fleetCompany;
}
public void setFleetCompany(FleetCompany fleetCompany) {
this.fleetCompany = fleetCompany;
}
public int getServiceTypes() {
return serviceTypes;
}
public void setServiceTypes(int serviceTypes) {
this.serviceTypes = serviceTypes;
}
}
Some people told me to make a DTO:
public class WorkOrderDTO extends WorkOrder {
private String service_types;
public WorkOrderDTO() {
super();
}
public WorkOrderDTO(String service_types) {
this.service_types = service_types;
}
public String getService_types() {
return service_types;
}
public void setService_types(String service_types) {
this.service_types = service_types;
}
}
and add make the repository replaced from WorkOrder to WorkOrderDTO.
public interface WorkOrderRepository extends JpaRepository<WorkOrderDTO, Integer>
but when I do that I have autowiring problems.
I solved my own problem, finally!!!
I used #SqlResultMapping
SqlResultSetMapping(
name="workorder",
classes={
#ConstructorResult(
targetClass=WorkOrderDTO.class,
columns={
#ColumnResult(name="wo_number", type = Long.class),
#ColumnResult(name="service_types", type = String.class),
#ColumnResult(name="order_title", type = String.class)
}
)
}
)
And I created a new POJO that is not an entity named WorkOrderDTO.
#PersistenceContext
private EntityManager em;
#Override
public Collection<WorkOrderDTO> getWork() {
Query query = em.createNativeQuery(
"SELECT Sub1.wo_number, Sub2.service_types, Sub1.order_title FROM (SELECT * FROM workorder) Sub1 INNER JOIN (SELECT wo_number, GROUP_CONCAT(service_type SEPARATOR ', ') AS 'service_types' FROM service_type GROUP BY wo_number) Sub2 ON Sub1.wo_number=Sub2.wo_number WHERE fleet_company_id=4 AND (order_status='On-Bidding' OR order_status='Draft')", "workorder");
#SuppressWarnings("unchecked")
Collection<WorkOrderDTO> dto = query.getResultList();
Iterable<WorkOrderDTO> itr = dto;
return (Collection<WorkOrderDTO>)itr;
}
At last, the users who hated me for posting the same problem won't be annoyed anymore.

detached entity passed to persist for batch insert in JPA

For the following batch insert method, i get this exception "detached entity passed to persist". Could you take a look at this method and give me some hints?
Thank you so much.
if needed, I will provided the entities here, for the moment I provide Keyword entity :
public class Keyword implements Serializable {
private static final long serialVersionUID = -1429681347817644570L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="key_id")
private long keyId;
#Column(name="key_name")
private String keyName;
#ManyToOne
#JoinColumn(name="tweet_id")
private Tweet tweet;
public long getKeyId() {
return keyId;
}
public void setKeyId(long keyId) {
this.keyId = keyId;
}
public String getKeyName() {
return keyName;
}
public void setKeyName(String keyName) {
this.keyName = keyName;
}
public Tweet getTweet() {
return tweet;
}
public void setTweet(Tweet tweet) {
this.tweet = tweet;
}
}
Here Tweet Entity :
#Entity
#Table(name="tweets")
public class Tweet implements Serializable{
#Id
#Column(name="tweet_id")
private long tweetId;
#Column(name="tweet_text")
private String tweetText;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created_at")
private Date createdAt;
#Column(name="lang_code")
private String languageCode;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
#OneToMany(mappedBy="tweet")
//#JoinColumn(name="hashtag_id")
private List<Hashtag> hashtags;
#OneToMany(mappedBy="tweet")
//#JoinColumn(name="url_id")
private List<Url> urls;
public List<Keyword> getKeywords() {
return keywords;
}
public void setKeywords(List<Keyword> keywords) {
this.keywords = keywords;
}
#OneToMany(mappedBy="tweet")
//#JoinColumn(name="url_id")
private List<Keyword> keywords;
public long getTweetId() {
return tweetId;
}
public void setTweetId(long tweetId) {
this.tweetId = tweetId;
}
public String getTweetText() {
return tweetText;
}
public void setTweetText(String tweetText) {
this.tweetText = tweetText;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public String getLanguageCode() {
return languageCode;
}
public void setLanguageCode(String languageCode) {
this.languageCode = languageCode;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<Hashtag> getHashtags() {
return hashtags;
}
public void setHashtags(List<Hashtag> hashtags) {
this.hashtags = hashtags;
}
public List<Url> getUrls() {
return urls;
}
public void setUrls(List<Url> urls) {
this.urls = urls;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (tweetId ^ (tweetId >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Tweet other = (Tweet) obj;
if (tweetId != other.tweetId)
return false;
return true;
}
And here Url entity :
#Entity
#Table(name="tweet_url")
public class Url implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="url_id")
private int urlId;
#Column(name="url")
private String url;
#ManyToOne
#JoinColumn(name="tweet_id",referencedColumnName="tweet_id")
private Tweet tweet;
public int getUrlId() {
return urlId;
}
public void setUrlId(int urlId) {
this.urlId = urlId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Tweet getTweet() {
return tweet;
}
public void setTweet(Tweet tweet) {
this.tweet = tweet;
}
And here is hashtag entity :
#Entity
#Table(name="tweet_hashtag")
public class Hashtag implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="hashtag_id")
private int hashtagId;
#Column(name="hashtag")
private String hashtag;
#ManyToOne
#JoinColumn(name="tweet_id",referencedColumnName="tweet_id")
private Tweet tweet;
public int getHashtagId() {
return hashtagId;
}
public void setHashtagId(int hashtagId) {
this.hashtagId = hashtagId;
}
public String getHashtag() {
return hashtag;
}
public void setHashtag(String hashtag) {
this.hashtag = hashtag;
}
public Tweet getTweet() {
return tweet;
}
public void setTweet(Tweet tweet) {
this.tweet = tweet;
}
And the method :
public void batchInsert(List<Keyword> results) throws HibernateException {
// chekeywordck if key exists
// try {
em=RunQuery.emf.createEntityManager();
em.getTransaction().begin();
for(Keyword result:results)
{
try{
em.persist(result.getTweet().getUser());
}
catch(ConstraintViolationException ce)
{
System.out.print("duplicated insert catched");
}
try{
em.persist(result.getTweet());
}
catch(ConstraintViolationException ce)
{
System.out.print("duplicated insert catched");
}
if(result.getTweet().getHashtags()!=null)
for(Hashtag hashtag:result.getTweet().getHashtags())
em.persist(hashtag);
if(result.getTweet().getUrls()!=null)
for(Url url:result.getTweet().getUrls())
em.persist(url);
em.persist(result);
em.flush();
em.clear();
//when I put these two line out of this loop, it still is the same.
}
em.getTransaction().commit();
// }
}
And here is the exception :
Exception in thread "Thread-3" javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: model.twitter.entities.Url
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1187)
at model.service.QueryResultService.batchInsert(QueryResultService.java:74)
at controller.ResultsController.save(ResultsController.java:125)
at controller.ResultsController.parse(ResultsController.java:89)
at main.TwitterStreamConsumer.run(TwitterStreamConsumer.java:41)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: model.twitter.entities.Url
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:139)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181)
... 5 more
To answer your question: your model defines a one-to-many relationship between Tweet and URL without any cascading. When you are passing a Tweet instance for persisting, the URL objects have not yet been saved and your model does not mandate Tweet to cascade the persist operation to the URL instances. Therefore it can not create the relationship with them.
Cascading tells the hibernate, how to execute DB operations on related entities.
You can instruct it to pass/cascade the persist operation to the related entity, to cascade all operations or an array of operations.
That being said, your problem(1 of them) could be fixed if you modify the relationship with cascading info:
#OneToMany(mappedBy="tweet", cascade={CascadeType.PERSIST})
private List<Url> urls;
But your sample indicates other possible issues and I would encourage you to spent some more time reading Hibernate ORM documentation and practicing on sample model with less relationships.
One of the obvious issues seems to be the lack of understanding of relationship owner concept.
For example, in your Tweet-to-Url relationship, URL is the relationship owner(responsible for managing the relationship, e.g. managing the link via foreign key)
Please consult hibernate docs or one of hundreds of similar questions here on SO for more info.
Depending on how you fill the data, it is possible that you will run into constraint issues, or your entities will not be linked together, because you are not saving the owning side.
Also using try/catch for constraint violations is a very bad way of detecting duplicated entries. ConstraintViolationException can be have many causes and the reason you are getting them is related to the above mentioned relationship mapping issues.
ORM is complex subject and it is really beneficial to start with smaller examples, trying to understand the framework mechanics before moving to the more challenging models. Good Luck
For all the persist calls try using this instead:
if(result.getTweet().getUser().getId() == null) {
em.persist(result.getTweet().getUser());
} else {
result.getTweet().setUser(em.merge(result.getTweet().getUser()));
}
if(result.getTweet().getId() == null) {
em.persist(result.getTweet());
} else {
result.setTweet(em.merge(result.getTweet()));
}
if(result.getId() == null) {
em.persist(result);
} else {
result = em.merge(result);
}

JPQL createQuery is incompatible with query return type Collection

I want to get my profile in class Tournee (profil_tournee) list based on my tours ("tournee"). However, I have an exception. Can anyone help me?
Exception in thread "AWT-EventQueue-0"
java.lang.IllegalArgumentException: Type specified for TypedQuery
[fr.galettedebroons.domain.Profil] is incompatible with query return
type [interface java.util.Collection]
Request:
List<List<Profil>> listProfil = Arrays.asList(manager_.createQuery("select t.profil_tournee "
+ "FROM Tournee t WHERE t.nom LIKE :tournee", Profil.class)
.setParameter("tournee", tournee)
.getResultList());
Model :
#Entity
public class Tournee {
private int id;
private String nom;
private boolean lundi = false;
private boolean mardi = false;
private boolean mercredi = false;
private boolean jeudi = false;
private boolean vendredi = false;
private boolean samedi = false;
private boolean dimanche = false;
private List<Profil> profil_tournee;
public Tournee(){}
public Tournee(String nom, boolean lundi, boolean mardi, boolean mercredi, boolean jeudi,
boolean vendredi, boolean samedi, boolean dimanche, List<Profil> profil_tournee) {
this.nom = nom;
this.lundi = lundi;
this.mardi = mardi;
this.mercredi = mercredi;
this.jeudi = jeudi;
this.vendredi = vendredi;
this.samedi = samedi;
this.dimanche = dimanche;
this.profil_tournee = profil_tournee;
}
public Tournee(String nom, boolean lundi, boolean mardi, boolean mercredi, boolean jeudi,
boolean vendredi, boolean samedi, boolean dimanche) {
this.nom = nom;
this.lundi = lundi;
this.mardi = mardi;
this.mercredi = mercredi;
this.jeudi = jeudi;
this.vendredi = vendredi;
this.samedi = samedi;
this.dimanche = dimanche;
}
#Id #GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id_tournee) {
this.id = id_tournee;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public boolean isLundi() {
return lundi;
}
public void setLundi(boolean lundi) {
this.lundi = lundi;
}
public boolean isMardi() {
return mardi;
}
public void setMardi(boolean mardi) {
this.mardi = mardi;
}
public boolean isMercredi() {
return mercredi;
}
public void setMercredi(boolean mercredi) {
this.mercredi = mercredi;
}
public boolean isJeudi() {
return jeudi;
}
public void setJeudi(boolean jeudi) {
this.jeudi = jeudi;
}
public boolean isVendredi() {
return vendredi;
}
public void setVendredi(boolean vendredi) {
this.vendredi = vendredi;
}
public boolean isSamedi() {
return samedi;
}
public void setSamedi(boolean samedi) {
this.samedi = samedi;
}
public boolean isDimanche() {
return dimanche;
}
public void setDimanche(boolean dimanche) {
this.dimanche = dimanche;
}
#OneToMany(mappedBy="profil_tournee", cascade=CascadeType.PERSIST)
public List<Profil> getProfil_tournee() {
return profil_tournee;
}
public void setProfil_tournee(List<Profil> profil_tournee) {
this.profil_tournee = profil_tournee;
}
}
#Entity
public class Profil {
private String code_client;
private Client client_profil;
private Gamme gamme_profil;
private List<Livraison> livraison_profil;
private Boolean actif;
private Tournee profil_tournee;
private List<MargeLivraison> marge_profil;
private List<Prevision> prevision_profil;
public Profil(){}
public Profil(Gamme code_gamme, List<Livraison> livraison, Boolean actif) {
this.gamme_profil = code_gamme;
this.livraison_profil = livraison;
this.actif = actif;
}
#Id
public String getCode_client() {
return code_client;
}
public void setCode_client(String code_client) {
this.code_client = code_client;
}
public Boolean getActif() {
return actif;
}
public void setActif(Boolean actif) {
this.actif = actif;
}
#ManyToOne
public Gamme getGamme_profil() {
return gamme_profil;
}
public void setGamme_profil(Gamme gamme_profil) {
this.gamme_profil = gamme_profil;
}
#OneToMany(mappedBy="livraison_profil", cascade=CascadeType.PERSIST)
public List<Livraison> getLivraison_profil() {
return livraison_profil;
}
public void setLivraison_profil(List<Livraison> livraison_profil) {
this.livraison_profil = livraison_profil;
}
#ManyToOne
public Client getClient_profil() {
return client_profil;
}
public void setClient_profil(Client client) {
this.client_profil = client;
}
#ManyToOne
public Tournee getProfil_tournee() {
return profil_tournee;
}
public void setProfil_tournee(Tournee profil_tournee) {
this.profil_tournee = profil_tournee;
}
#OneToMany(mappedBy="marge_profil", cascade=CascadeType.PERSIST)
public List<MargeLivraison> getMarge_profil() {
return marge_profil;
}
public void setMarge_profil(List<MargeLivraison> marge_profil) {
this.marge_profil = marge_profil;
}
#OneToMany(mappedBy="prevision_profil", cascade=CascadeType.PERSIST)
public List<Prevision> getPrevision_profil() {
return prevision_profil;
}
public void setPrevision_profil(List<Prevision> prevision_profil) {
this.prevision_profil = prevision_profil;
}
Your expected result list will contain elements that are list of profiles, not profiles.
I would replace Profil.class by List.class for the Query creation :
List<List<Profil>> listProfil = Arrays.asList(manager_.createQuery("select t.profil_tournee "
+ "FROM Tournee t WHERE t.nom LIKE :tournee", List.class)
.setParameter("tournee", tournee)
.getResultList());
Your error gives you a hint that the returning type should be consistent with declared type when invoking EntityManager.createQuery(query, Type) method:
List<SomeType> em.createQuery("SELECT s FROM SomeType", SomeType.class);
However your real problem is that your query is illegal. In JPA collection-valued expressions cannot be part of SELECT clause. Please see another answer of mine https://stackoverflow.com/a/25890863/3796586.
The solution in your case would be to reverse the query like this:
List<Profil> result = em.createQuery("SELECT p FROM Profil p WHERE" +
"p.profil_tournee.norm LIKE :tournee", Profil.class)
.setParameter("tournee", tournee)
.getResultList());

How does Spring Data (MongoDB) read an object?

I am currently working on a project using the Spring framework and SpringData MongoDB (v.1.6.1 RELEASE). I now want to add a property to a stored object, that would simplify its retrieval, but I need to compute this property based on the state of the object at the point of time I want to save it. I tried to put that computation within the getter method of the object, but somehow SpringData is not using the getter to access the property.
The concrete example is the following:
I am storing events in the database and the events are allowed to span over several dates, creating a multi-date event. The events are defined by a start date (LocalDateTime) and an end date (LocalDateTime). I now want to store the information, if the event is a multi-date event or not, within the database. Concluding I added a boolean variable to the event (multiDate). Within the getter (isMultiDate) I am comparing the start and end date and returning true or false (depending on the dates).
My event object:
public class Event
{
#Id
private String id;
#NotBlank
private String name;
private String description;
private String location;
private double locationLat;
private double locationLog;
#NotNull
#JsonIgnore
private int startDateDayOfMonth, startDateMonth, startDateYear, startDateHour, startDateMinute;
#NotNull
#JsonIgnore
private int endDateDayOfMonth, endDateMonth,endDateYear, endDateHour, endDateMinute;
#LastModifiedDate
private Date lastChanged;
#Transient
private LocalDateTime startDateTime;
#Transient
private LocalDateTime endDateTime;
private boolean multiDate;
#DBRef
#NotEmpty
private List<Division> invitedDivision;
public Event() {}
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public String getLocation()
{
return location;
}
public void setLocation(String location)
{
this.location = location;
}
public double getLocationLat()
{
return locationLat;
}
public void setLocationLat(double locationLat)
{
this.locationLat = locationLat;
}
public double getLocationLog()
{
return locationLog;
}
public void setLocationLog(double locationLog)
{
this.locationLog = locationLog;
}
public int getStartDateDayOfMonth()
{
return startDateDayOfMonth;
}
public void setStartDateDayOfMonth(int startDateDayOfMonth)
{
this.startDateDayOfMonth = startDateDayOfMonth;
}
public int getStartDateMonth()
{
return startDateMonth;
}
public void setStartDateMonth(int startDateMonth)
{
this.startDateMonth = startDateMonth;
}
public int getStartDateYear()
{
return startDateYear;
}
public void setStartDateYear(int startDateYear)
{
this.startDateYear = startDateYear;
}
public int getStartDateHour()
{
return startDateHour;
}
public void setStartDateHour(int startDateHour)
{
this.startDateHour = startDateHour;
}
public int getStartDateMinute()
{
return startDateMinute;
}
public void setStartDateMinute(int startDateMinute)
{
this.startDateMinute = startDateMinute;
}
public int getEndDateDayOfMonth()
{
return endDateDayOfMonth;
}
public void setEndDateDayOfMonth(int endDateDayOfMonth)
{
this.endDateDayOfMonth = endDateDayOfMonth;
}
public int getEndDateMonth()
{
return endDateMonth;
}
public void setEndDateMonth(int endDateMonth)
{
this.endDateMonth = endDateMonth;
}
public int getEndDateYear()
{
return endDateYear;
}
public void setEndDateYear(int endDateYear)
{
this.endDateYear = endDateYear;
}
public int getEndDateHour()
{
return endDateHour;
}
public void setEndDateHour(int endDateHour)
{
this.endDateHour = endDateHour;
}
public int getEndDateMinute()
{
return endDateMinute;
}
public void setEndDateMinute(int endDateMinute)
{
this.endDateMinute = endDateMinute;
}
public Date getLastChanged()
{
return lastChanged;
}
public void setLastChanged(Date lastChanged)
{
this.lastChanged = lastChanged;
}
public LocalDateTime getStartDateTime()
{
startDateTime = LocalDateTime.of(startDateYear, startDateMonth, startDateDayOfMonth, startDateHour, startDateMinute);
return startDateTime;
}
public void setStartDateTime(LocalDateTime startDateTime)
{
this.startDateTime = startDateTime;
if(startDateTime != null)
{
startDateYear = startDateTime.getYear();
startDateMonth = startDateTime.getMonthValue();
startDateDayOfMonth = startDateTime.getDayOfMonth();
startDateHour = startDateTime.getHour();
startDateMinute = startDateTime.getMinute();
}
}
public LocalDateTime getEndDateTime()
{
endDateTime = LocalDateTime.of(endDateYear, endDateMonth, endDateDayOfMonth, endDateHour, endDateMinute);
return endDateTime;
}
public void setEndDateTime(LocalDateTime endDateTime)
{
this.endDateTime = endDateTime;
if(endDateTime != null)
{
endDateYear = endDateTime.getYear();
endDateMonth = endDateTime.getMonthValue();
endDateDayOfMonth = endDateTime.getDayOfMonth();
endDateHour = endDateTime.getHour();
endDateMinute = endDateTime.getMinute();
}
}
public List<Division> getInvitedDivision()
{
return invitedDivision;
}
/**
* The function is setting all invited divisions, but is optimizing the set by eliminating unnecessary divisions.
* #param invitedDivision
*/
public void setInvitedDivision(List<Division> invitedDivision)
{
if(invitedDivision != null)
{
this.invitedDivision = DivisionManagementController.getOptimizedSetOfDivisions(invitedDivision);
} else
{
this.invitedDivision = invitedDivision;
}
}
public void addDivision(Division division)
{
if(invitedDivision == null)
{
invitedDivision = new ArrayList<>();
}
invitedDivision.add(division);
}
public boolean isMultiDate()
{
return (startDateDayOfMonth != endDateDayOfMonth) || (startDateMonth != endDateMonth) || (startDateYear != endDateYear);
}
public void setMultiDate(boolean multiDate)
{
this.multiDate = multiDate;
}
}
What am I getting wrong? Why is SpringData not using the public getter to access a private variable? (I actually returned always true and the database still only showed storing false).
Thanks in advance!
I am still not clear about the issue, but try this
public boolean isMultiDate()
{
multiDate = (startDateDayOfMonth != endDateDayOfMonth) || (startDateMonth != endDateMonth) || (startDateYear != endDateYear);
return multiDate;
}

Categories