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,'')
;
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 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 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.
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.