unable to update objects of one to one relation in hibernate - sql

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.

Related

Referential integrity constraint violation (CAST( AS BIGINT))

I am creating a database of items and have been trying to assign multiple database entities to a single item however I am struggling to get past an error I keep having. I am unsure what I am doing wrong can someone help?
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Referential integrity constraint violation: "FKKPIB0GWXM6UFS3SJJ2NCI64AR: PUBLIC.FEATURES FOREIGN KEY(ITEM_ID) REFERENCES PUBLIC.ITEM(ITEM_ID) (CAST(1020 AS BIGINT))"; SQL statement: INSERT INTO FEATURES(FEATURE_ID, ITEM_ID) VALUES(101, 1020), (102,1021), (103,1021), (104,1021)
Item.java
#Entity
#Table(name="item")
public class Item {
#Id
#Column(name = "item_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#Enumerated(EnumType.STRING)
private ItemType itemtype;
private int weight;
private int recovers;
private int priority;
private String desc;
#OneToMany(mappedBy = "item")
private List<Feature> features;
}
Feature.java
#Entity
#Table(name = "features")
public class Feature {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long feature_id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "item_id", insertable = false, updatable = false)
#JsonIgnore
private Item item;
}
data.sql
INSERT INTO SPELLS(SPELL_ID, ITEM_ID)
VALUES(101, 1020),
(102, 1021),
(103, 1021),
(104, 1021)
;
INSERT INTO ITEM(ITEM_ID, NAME, ITEMTYPE, WEIGHT, RECOVERS, PRIORITY, DESC)
VALUES (1010,'Hunting Knife','DAGGER',1,5,3,''),
(1011,'Relic Sword','SWORD',3,10,3,''),
(1012,'Relic Spear','SPEAR',3,8,3, ''),
(1013,'Relic Axe','AXE',4,12,3, ''),
(1014,'Old Club','MACE',4,10,3,''),
(1015,'Crooked Stick','STAFF',2,3,3,''),
(1016,'Training Bow','BOW',2,20,4,''),
(1017,'Training Crossbow','CROSSBOW',2,20,4,''),
(1018,'Grass Sling','SLING',2,20,4,''),
(1019,'Wooden Shield','SHIELD',4,20,4,''),
(1020,'Poison wand','WAND', 1,0,4,''),
(1021,'Mushroom staff','STAFF',2,3,3,'')
;

Nested query in JPQL

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.

EclipseLink- JPQL join tables through query

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

Hiberate search for child entities

I have three classes defined as:
1)Category class:-
#Entity
#Table(name = "CATEGORY")
#Data
#NoArgsConstructor
#AllArgsConstructor
#Indexed
public class Category {
#Id
#GeneratedValue
private Long id;
#Field(index = Index.YES, store = Store.YES, analyzer = #Analyzer(definition = "ngram"))
private String categoryName;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "categoryId", referencedColumnName = "id")
#LazyCollection(LazyCollectionOption.TRUE)
#IndexedEmbedded
private List<SubCategory> subCategories;
private Long creationTime;
private Long updationTime;
}
2) SubCategory class:-
#Entity
#Table(name = "SUB_CATEGORY")
#Data
#NoArgsConstructor
#AllArgsConstructor
#Indexed
public class SubCategory {
#Id
#GeneratedValue
private Long id;
#Field(index = Index.YES,store = Store.YES,analyzer = #Analyzer(definition = "ngram1"))
private String subCategoryName;
#Field(index = Index.YES,store = Store.YES)
private Long categoryId;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "subCategoryId", referencedColumnName = "id")
#LazyCollection(LazyCollectionOption.TRUE)
#IndexedEmbedded
private List<Pages> pages;
private Long creationTime;
}
3) Pages class:-
#Entity
#Table(name = "PAGES")
#Data
#NoArgsConstructor
#AllArgsConstructor
#Indexed
public class Pages {
#Id
#GeneratedValue
private Long id;
#Field(index = Index.YES,store = Store.YES,analyzer = #Analyzer(definition = "ngram2"))
private String pageName;
#Field(index = Index.YES,store = Store.YES,analyzer = #Analyzer(definition = "ngram2"))
private String pageDescription;
#Field(index = Index.YES,store = Store.YES,analyzer = #Analyzer(definition = "ngram2"))
private Long subCategoryId;
private Long creationTime;
}
Now the data is defined like:-
Category SubCategory Pages
-------- ------------ -------
Vehicle Car BMW
Electricals MotorCycle Hero
........... ........ Audi
........... ........ ......
Lapzz Laptop ......
Dell
Now I am stuck at getting the query that will search in all three classes using hibernate search(i.e.-If I search Lap*) I should get result from Categories,Subcategories and Pages and only the rows matching the query only not the complete object of Category.
eg-I should get in the result set the row containing Lapzz in categories and row containing Laptop in subcategories when I search for Lap*.
Please help my find this solution.
This should do what you want, as far as I understand:
String searchTerms = ...;
QueryBuilder categoryQb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity( Category.class ).get();
QueryBuilder subCategoryQb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity( SubCategory.class ).get();
QueryBuilder pagesQb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity( Pages.class ).get();
Query categoryQuery = categoryQb.keyword()
.onField( "categoryName" )
.matching( searchTerms )
.createQuery();
Query subCategoryQuery = subCategoryQb.keyword()
.onField( "subCategoryName" )
.matching( searchTerms )
.createQuery();
Query pagesQuery = pagesQb.keyword()
.onFields(
"pageName",
"pageDescription"
)
.matching( searchTerms )
.createQuery();
Query luceneQuery = categoryQb.bool()
.should( categoryQuery )
.should( subCategoryQuery )
.should( pagesQuery )
.createQuery();
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(
luceneQuery,
Category.class, SubCategory.class, Pages.class
);
List<?> results = fullTextQuery.getResultList();
Several warnings are necessary here:
since you are using ngram filters, you may need to use a different analyzer when querying; see this answer
your #Field annotation on Pages.subcategoryId is highly suspicious: it doesn't make sense to analyze a numeric value. For that matter, it's suspicious to store the ID of another entity in Pages, you'd generally want to have a field whose type is SubCategory instead and annotate it with #ManyToOne.
if you want your query to match a category that doesn't have the search terms in its description, but contains a page whose name or description contains the search terms, you will have to add an IndexedEmbedded and add the embedded fields ("pages.pageName", "pages.pageDescription", ...) to your search queries.

Duplicate data from JPA query (sql constraint)

For some reason I'm returning 9 rows of duplicate data using this query in my repository.
#Query("select distinct profile from OfficeProfile profile where profile.fcoDesignCd in
(select officeLocation.asccode from OfficeLocation officeLocation, OfficeProfile profile
where officeLocation.statecode = :stateCode and officeLocation.asccode = profile.fcoDesignCd)")
public List<OfficeProfile> searchStateASC(#Param("stateCode") String stateCode);
The sql query that returns 9 distinct rows of data is below. The queries appear to be identical.
select
op.FCO_DESIGN_CD,
op.office_addr_line1,
op.office_addr_line2,
op.office_addr_state,
op.office_addr_zip
from cridba.office_profile op
where op.fco_design_cd in (
select asc_code from cridba.cris_lk_location cll , cridba.office_profile op
where cll.state_code='VA'
and cll.asc_code = op.fco_design_cd);
This is how I'm iterating over the values. I set my debugger and noticed the same 9 values with ids.
for(OfficeProfile locationInfo: officeLocatorRepository.searchStateASC(stateCode))
Here are my entity relationships.
Office Profile (Parent)
#OneToMany(cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
mappedBy = "profile")
private Set<OfficeLocation> officeLocation = new HashSet<>(0);
Office Location (Child)
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "asc_code", referencedColumnName = "fco_design_cd", nullable = false, insertable=false,
updatable=false)
public OfficeProfile profile;
I'm overriding equals and hashcode in both classes. Since I'm joining these tables using asc_code do i override that or id? or both? Here is what I have so far.
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
OfficeProfile officeProfile = (OfficeProfile) o;
if (officeProfile.getId() == null || getId() == null) {
return false;
}
return Objects.equals(getId(), officeProfile.getId());
}
#Override
public int hashCode() {
return Objects.hashCode(getId());
}
Should I add #Id to fcoDesignCd even though this table already has an id? fcoDesignCd is the referenced column in join?
#Column(name = "fco_design_cd")
private String fcoDesignCd;
HQL output...
select distinct officeprof0_.office_type_id as office_type_id1_1_, ......
from cridba.office_profile officeprof0_ where officeprof0_.fco_design_cd in
(select officeloca1_.asc_code
from cridba.cris_lk_location officeloca1_, cridba.office_profile
officeprof2_ where officeloca1_.state_code=? and
officeloca1_.asc_code=officeprof2_.fco_design_cd)
Does this look like the right path to take? JPA How add unique contraint on column for #OneToMany relation like on username
You shouldn't add another #Id column for your table, since you already have one. Make sure that its backed up with a unique constraint in the database.
The overriding of hashCode and equals looks ok also.
The problem with duplicates is probably in the query.