I have this relationship in db. In the Item table the primary keys are Item_id and site. ItemPart table's primary keys are also them and there are other 2 primary keys as well. These tables are join by item_id and site as one to many relationships.
These are the 2 entity classes.
public class Item {
#Id
#Column(name = "item_id", updatable = false, nullable = false)
private String itemId;
#Id
#Column(name = "site", updatable = false, nullable = false)
private String site;
#OneToMany(mappedBy = "item")
private List<ItemPart> itemPart;
...
public class ItemPart {
#Id
#Column(name = "item_id", updatable = false, nullable = false)
private String itemId;
#Id
#Column(name = "site", updatable = false, nullable = false)
private String site;
#ManyToOne
#JoinColumns({
#JoinColumn(name = "item_id", referencedColumnName = "item_id", insertable = false, updatable = false),
#JoinColumn(name = "site", referencedColumnName = "site", insertable = false, updatable = false)
})
private Item item;
...
What I want is when giving an item_id return a result like below. If I give item_id = "100" and there is one item with item_id = 100 and 2 itemParts with item_id =100 and site=S01.
{
"Item":[
{
"item_id":"100",
"site":"S01",
"itemPart":[
{
"item_id":"100",
"site":"S01",
"another_pk": "x"
},
{
"item_id":"100",
"site":"S01",
"another_pk": "y"
}
],
...
}
]
But actually, it returns 2 similar item objects with each of them 2 itemPart objects. Like this.
{
item:
itemPart:[
{...},
{...}
]
},
{
item:
itemPart:[
{...},
{...}
]
}
I want to fix this and I'm using JPA. Can anyone find where is the problem here.
#Query("SELECT p FROM Item p JOIN fetch p.ItemPart n WHERE
p.item_id = ?1 ")
List<Item> findAllByItemId(String itemId);
You should correct your query like this:
#QueryHints(value = {
#QueryHint(name = org.hibernate.jpa.QueryHints.HINT_PASS_DISTINCT_THROUGH, value = "false")
})
#Query("select distinct p from Item p join fetch p.itemPart where p.itemId = :itemId ")
List<Item> findAllByItemId(#Param("itemId") String itemId);
See also this section of hibernate documentation.
I put 'distinct' in the #Query then the problem was solved.
#Query("SELECT distinct p FROM Item p JOIN fetch p.ItemPart n WHERE
p.item_id = ?1 ")
List<Item> findAllByItemId(String itemId);
Related
I have 2 entities -
#Table(name = "MM_MONITORING_CARD")
#Entity(name = "mm_MonitoringCard")
public class MonitoringCard extends StandardEntity {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CLIENT_ID")
private Counterparty client;
#Column(name = "START_DATE")
private LocalDate startDate;
#Column(name = "END_DATE")
private LocalDate endDate;
...otherColumn
}
and
#DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING)
#Table(name = "MM_COUNTERPARTY")
#Entity(name = "mm_Counterparty")
#DiscriminatorValue("COUNTERPARTY")
#NamePattern("%s|name")
public class Counterparty extends StandardEntity {
#Column(name = "TYPE", insertable=false, updateable=false)
private String type;
...otherColumn
I need get all examples monitoringCard with condition - 1) between start date and end date 2) with Counterparty type = 'someType'
I do method -
List<MonitoringCard> monitoringCardList = dataManager.load(MonitoringCard.class)
.query("select distinct cm from mm_MonitoringCard m join mm_Counterparty cm where (m.current_date between cm.startDate and cm.endDate) and cm.type = :type")
.parameter("type", "someType")
.list();
but i get error, how can i make a correct request?
thanks
Your query is not correct. It should use a join like this:
select distinct m.Counterparty from mm_MonitoringCard m
where (m.current_date between m.Counterparty.startDate and m.Counterparty.endDate)
and m.Counterparty.type = :type
In JPA you don't need to do an explicit join when navigating on a ToOne relationship.
I am getting following error after starting my spring application:
Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryException: cannot dereference scalar collection element: metadata_descriptor_id [SELECT d FROM com.org.entity.documents.Document d INNER JOIN d.documentMetadata md ON md.document_id = d.id WHERE (md.metadata_descriptor_id.id NOT IN (:documentMetadataId))]
Here is my Document class:
#Entity
#Table(name = "documents")
public class Document {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "name", nullable = false, unique = true)
private String name;
#Column(name = "archived", nullable = false)
private boolean archived;
#Column(name = "creation_date", nullable = false)
private Instant creationDate;
#Column(name = "file_text_processing_status", nullable = false)
#Enumerated(EnumType.STRING)
private FileTextProcessingStatus fileTextProcessingStatus;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "template_file_id", referencedColumnName = "id")
private TemplateFile templateFile;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "state_descriptor_id", referencedColumnName = "id")
private StateDescriptor stateDescriptor;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "user_id", referencedColumnName = "id")
private UserEntity user;
#ElementCollection(targetClass = String.class)
#Column(name = "tag", nullable = false)
#CollectionTable(name = "document_tags", joinColumns = #JoinColumn(name = "document_id"))
private Set<String> tags = new HashSet<>();
#ElementCollection
#CollectionTable(name = "document_metadata", joinColumns = {
#JoinColumn(name = "document_id", referencedColumnName = "id")})
#MapKeyJoinColumn(name = "metadata_descriptor_id", referencedColumnName = "id")
#Column(name = "value", nullable = false)
private Map<MetadataDescriptor, String> documentMetadata = new HashMap<>();
#OneToMany(mappedBy = "document", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<DocumentFileVersion> documentVersions = new HashSet<>();`enter code here`
And here is Repository method that fails:
#Lock(LockModeType.PESSIMISTIC_WRITE)
#Query(value = "SELECT d FROM Document d INNER JOIN d.documentMetadata md ON md.document_id = d.id"
+ " WHERE (md.metadata_descriptor_id NOT IN (:documentMetadataId))")
List<Document> findAllByDocumentRequiredMetadataNotSet(long documentMetadataId);
I have seen an answer for similar question here: getting Caused by: org.hibernate.QueryException: cannot dereference scalar collection element: roles
But it's not helpful in my case. I will be very glad for any suggestions.
The type of md is String this is why you see an error. What you need is something like this:
#Lock(LockModeType.PESSIMISTIC_WRITE)
#Query(value = "SELECT d FROM Document d INNER JOIN d.documentMetadata md WHERE (KEY(md).id NOT IN (:documentMetadataId))")
List<Document> findAllByDocumentRequiredMetadataNotSet(long documentMetadataId);
You also had a ON clause which is no necessary/wrong. I think you should read into HQL/JPQL first as you don't seem to understand that a join of an association, will add the join predicate in the SQL automatically.
Note though, that the syntax KEY(..).id is only supported in newer Hibernate versions, so you might have to update.
I have problem with my JPQl. this is a one to many relationship with TrainRoute and TrainRouteStation. I'm trying to create a inner join and fetch the data. native SQL query working when I used mysql workbeanch and I'm trying convert it to JPQL. also, I was trying to fix from 2 days.
Error : Object comparisons can only be used with OneToOneMappings. Other mapping comparisons must be done through query keys or direct attribute level comparisons.
Class: TrainRoute
#Basic(optional = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "train_route_id", unique = true, nullable = false)
public Long getTrainRouteId() {
return this.trainRouteId;
}
public void setTrainRouteId(Long trainRouteId) {
this.trainRouteId = trainRouteId;
}
#OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER, mappedBy = "trainRoute")
public List<TrainRouteStationData> getTrainRouteStations() {
return this.trainRouteStations;
}
public void setTrainRouteStations(List<TrainRouteStationData> trainRouteStations) {
this.trainRouteStations = trainRouteStations;
}
Class: TrainRouteStation
#Basic(optional = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "train_route_station_id", unique = true, nullable = false)
public Long getTrainRouteStationId() {
return this.trainRouteStationId;
}
public void setTrainRouteStationId(Long trainRouteStationId) {
this.trainRouteStationId = trainRouteStationId;
}
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "train_route_id", nullable = false)
public TrainRouteData getTrainRoute() {
return this.trainRoute;
}
JPQL :"SELECT s FROM TrainRouteData t inner join TrainRouteStationData s ON t.trainRouteId=s.trainRoute where s.stationSeqN >=1 AND s.stationSeqN <=3 AND t.trainRouteDescX='Test1-Test2' order by s.stationSeqN asc"
Native SQL : SELECT train_route_station.* FROM train_route inner join train_route_station ON train_route.train_route_id=train_route_station.train_route_id where train_route_station.station_seq_n >= 1 AND train_route_station.station_seq_n <= 3 AND train_route.train_route_desc_x='Test1-Test2' order by train_route_station.station_seq_n asc
And it throw an error:
Exception Description: Object comparisons can only be used with OneToOneMappings. Other mapping comparisons must be done through query keys or direct attribute level comparisons.
Mapping: [org.eclipse.persistence.mappings.DirectToFieldMapping[trainRouteId-->train_route.train_route_id]]
Expression: [
Query Key trainRouteId
How can I change that query?
That's not how joins work in JPQL.
The correct query is
select s from TrainRouteData t inner join t.trainRouteStations s
where s.stationSeqN >= 1
and s.stationSeqN <= 3
and t.trainRouteDescX = 'Test1-Test2'
order by s.stationSeqN asc
I got [42000] You have an error in your SQL syntax error when I execute the HQL below:
update Status set result=18 where (userByUserId.userName like 'administrator')
And this is the corresponding SQL:
update
status cross
join
set
result=18
where
userName like 'administrator'
The results I am getting are incorrect.
But another similar query is in working order:
select count(*) from Status where (userByUserId.userName like 'administrator')
the corresponding SQL:
select
count(*) as col_0_0_
from
status status0_ cross
join
user user1_
where
status0_.userId=user1_.userId
and (
user1_.userName like 'administrator'
)
Does anyone know what happened?
Here is the code(partly):
Status.java
#Table(name = "status")
#Entity
#KeyField("statusId")
public class Status implements Serializable {
private Integer result;
#Column(name = "result", nullable = false, insertable = true, updatable = true
, length = 10, precision = 0)
#Basic
public Integer getResult() {
return result;
}
private Integer userId;
#Column(name = "userId", nullable = false, insertable = true, updatable = true
, length = 10, precision = 0)
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
private User userByUserId;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "userId", referencedColumnName = "userId", nullable = false,
insertable = false, updatable = false)
public User getUserByUserId() {
return userByUserId;
}
}
User.java
#Table(name = "user")
#Entity
#KeyField("userId")
public class User implements Serializable {
private String userName;
#Column(name = "userName", nullable = false, insertable = true, updatable = true, length = 24,
precision = 0, unique = true)
#Basic
public String getUserName() {
return userName;
}
private Collection<Status> statusesByUserId;
#OneToMany(mappedBy = "userByUserId", cascade = CascadeType.ALL)
public Collection<Status> getStatusesByUserId() {
return statusesByUserId;
}
}
I have relation as shown bellow:
#Entity
#Table(name = "ORDER_", catalog = "smartorder")
public class Order implements Serializable {
/**
* serial version id
*/
private static final long serialVersionUID = 13875615L;
#Id
#Column(name = "ORDER_ID", unique = true, nullable = false)
#SequenceGenerator(name = "ORDER_ID_GEN", sequenceName = "ORDER_ID_SEQ")
#GeneratedValue(generator = "ORDER_ID_GEN")
private long orderId;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "INVOICE_ID", referencedColumnName = "INVOICE_ID")
private Invoice invoice;
// setters and getters
}
#Entity
#Table(name = "INVOICE_")
public class Invoice implements Serializable {
/**
* serial version id
*/
private static final long serialVersionUID = 13875612L;
#Id
#Column(name = "INVOICE_ID", unique = true, nullable = false)
#SequenceGenerator(name = "INVOICE_ID_GEN", sequenceName = "INVOICE_ID_SEQ")
#GeneratedValue(generator = "INVOICE_ID_GEN")
private int invoiceId;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "ORDER_ID", referencedColumnName = "ORDER_ID")
private Order order;
#Column(name = "SUB_TOTAL", precision = 6, nullable = false)
private double subTotal;
#Column(name = "SERVICE_TAX", precision = 6, nullable = false)
private double serviceTax;
#Column(name = "VAT", precision = 6, nullable = false)
private double vat;
#Column(name = "SURCHAARGE", precision = 6, nullable = false)
private double surChaarge;
#Column(name = "GRAND_TOTAL", precision = 6, nullable = false)
private double grandTotal;
//setters and getters
}
I am able to save the records properly. But when i am trying to update orders objects by setting invoice object to order object then the order object is nor persisting only invoice object is persisting.
Order o = getSession().load(Order.class,1L);
o.setInvoice(new Invoice(.........));
getSession().update(o);
in console I am able to see one SQL statement only,
insert into INVOICE_ (DISCOUNT, GRAND_TOTAL, ORDER_ID, ROUNDING, SERVICE_TAX, SUB_TOTAL, SURCHAARGE, VAT) values (?, ?, ?, ?, ?, ?, ?, ?)
Invoice Id is not getting update in Order table :(
Can anyone suggest whats the issue is.
Thanks in advance.....
This may depend on your unusual design.
With INVOICE_ID in ORDR_ and ORDER_ID in INVOICE_ you have both tables at the same time as parent and child of each other.
If your database uses foreign keys deleting and inserting will be hard.
You should use one type/table as parent, (e. g. Order, because it's normaly first) and the other as child (order_id will be in invoice_ table).
In your object model you can have both directions (see first example of http://docs.oracle.com/javaee/6/api/javax/persistence/OneToOne.html)
The issue is incorrect scenario in which you used your Entities/Tables and the one-to-one mapping style. The concept of One-To-One does not corresponed with your current design of both tables and entities.
Please, try to read more about one-to-one here: The concept for one-to-one mapping. Explain the mapping
And mostly take a deep look here: Hibernate – One-to-One example (Annotation), where you can find examples of the one-to-one mapping.
If you really would like to continue with one-to-one mapping you have to:
Remove the "INVOICE_ID" column from the "INVOICE_" table (surprising but a fact)
make the "ORDER_ID" column in the "INVOICE_" table as a primary key (another fact)
change the mapping of the Invoice entity to be more submissive (driven by Order entity)
Example of changes of the Invoice mapping:
// just a draft, to give you idea about the
// "submissive" side mapping.
// All the ID stuff of the Invoice is driven by its
// "Master" - Order
#GenericGenerator(name = "generator", strategy = "foreign",
parameters = #Parameter(name = "property", value = "order"))
#Id
#GeneratedValue(generator = "generator")
#Column(name = "ORDER_ID", unique = true, nullable = false)
public Integer getOrderId() {
return this.orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
#OneToOne(fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
public Order getOrder() {
return this.order;
}
Please, take it as a draft, to show how different the one-to-one concept is.