can anyone tell me where is the error in this example
#Entity
#Table(name = "ITEM")
public class Item implements Serializable
{
#Id
#GeneratedValue
#Column(name = "ID")
private Long id;
#Column(name = "NAME")
private String name;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "ID_ITEM",referencedColumnName="ID")
private List<ItemDetail> itemDetails;
second class
#Entity
#Table(name = "ITEM_DETAIL")
public class ItemDetail implements Serializable
{
#Id
#GeneratedValue
#Column(name = "ID")
private Long id;
#Column(name = "NAME")
private String name;
#Column(name = "ID_ITEM")
private Long itemId;
and the db
COMMIT;
CREATE TABLE item(
id serial PRIMARY KEY,
name VARCHAR(16)
);
CREATE TABLE item_detail(
ID serial PRIMARY KEY,
NAME VARCHAR(16),
ID_ITEM serial REFERENCES item (id)
);
COMMIT;
The error i got is
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into ITEM (NAME, ID) values (?, ?)
Hibernate: insert into ITEM_DETAIL (ITEM_ID, NAME, ID) values (?, ?, ?)
Hibernate: insert into ITEM_DETAIL (ITEM_ID, NAME, ID) values (?, ?, ?)
Exception in thread "main" org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:90)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
at com.mkyong.common.App.main(App.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:115)
Caused by: java.sql.BatchUpdateException: Batch entry 0 insert into ITEM_DETAIL (ITEM_ID, NAME, ID) values (NULL, id1, 161) was aborted. Call getNextException to see the cause.
at org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleError(AbstractJdbc2Statement.java:2530)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1317)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:350)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2592)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 13 more
Process finished with exit code 1
It's obviously that item_id is null but why??
Thanks
Regards
#backebg: can you check your db script and let us know that you executed exactly same in Database. If yes then either correct your entities to use "ID_ITEM" or item_detail table to use 'ITEM_ID' instead 'ID_ITEM'. thanks
Having ITEM_ID mapped as a column in ItemDetail is a bit odd, and mapping it that way might might be the source of the problem. Nothing is telling the ItemDetail class that that field should be populated with a proper id for the parent Item, including that it shouldn't be null.
If the detail doesn't need to know about the parent, you might be able to just omit that field in the ItemDetail java code altogether. The field in the table should be populated as a consequence of the relation.
It's more common to map this sort of thing as a bidirectional association, so that you have a #OneToMany relation of Item to ItemDetail and a #ManyToOne relation of ItemDetail to Item, and the relations can be navigated in Java. If the ItemDetail does need to know about the parent item, you should do it this way.
This is described somewhere in the Hibernate Annotations Reference section on mapping associations.
Use nullable = false to tell Hibernate that the join column cannot be null:
#Entity
#Table(name = "ITEM")
public class Item implements Serializable {
// ...
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "ID_ITEM", referencedColumnName = "ID", nullable = false)
private List<ItemDetail> itemDetails;
// ...
}
and remove the itemId property from ItemDetail as it is already mapped by the #JoinColumn annotation. If you need the itemId, then use a bi-directional relationship (hold a reference to the entire Item object, not just the ID).
Related
I have an entity Mealplan, where each weekday (enum) contains a meal. This is realised with a map and a Many-to-Many relation like this:
#Entity
public class Mealplan {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToMany
#SortNatural
private Map<Weekday, Meal> mealsPerWeek;
(...)
}
This means, in my database the mealsPerWeek property is stored in an extra table. "mealplan_meals_per_week". This table contains the mealplan_id, the meal_per_week_id (mealID) and the weekday_id.
Now, if I remove a Mealplan, everything gets deleted as I am expecting it. But if I want to delete a Meal, following SQL error occurs:
org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Referentielle Integrität verletzt: "FKPIBLWWQG1HR2D5W7BGORA9XBB: PUBLIC.ESSENSPLAN_ESSEN_PRO_WOCHE FOREIGN KEY(ESSEN_PRO_WOCHE_ID) REFERENCES PUBLIC.ESSEN(ID) (1)"
Referential integrity constraint violation: "FKPIBLWWQG1HR2D5W7BGORA9XBB: PUBLIC.ESSENSPLAN_ESSEN_PRO_WOCHE FOREIGN KEY(ESSEN_PRO_WOCHE_ID) REFERENCES PUBLIC.ESSEN(ID) (1)"; SQL statement:
delete from essen where id=? [23503-200]
I am expecting that If I delete a Meal, the line in mealplan gets deleted but everything else stays the same.
Note: CasdadeType.REMOVE is not an option, because it deletes every Mealplan too, where the meal i want to remove is in it.
#Entity
public class Essen {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
}
In mealplan_meals_per_week table there is a reference of Meal in meal_per_week_id column. So where you are trying to delete Meal without cascade reference can't be resolved.
So first delete the references of Meal in mealplan_meals_per_week table and then delete Meal.
Since you are not using Entity for mealplan_meals_per_week, you can use native SQL to define query using nativeQuery.
#Query(
value = "DELETE FROM mealplan_meals_per_week m WHERE m.meal_per_week_id= ?1",
nativeQuery = true)
void deleteByMealId(Interger mealId);
I have a database which has tables Entity1 and Entity2. Entity2 has a coinstraint which relates it to Entity1 : a simple FK-PK relationship.
I would now like to insert a row into table Entity1, and insert a corresponding row into table Entity 2. This has to be done in a single transaction. My attempt is below:
EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "BankingPU" );
EntityManager em = emfactory.createEntityManager();
em.getTransaction().begin();
//--- insert a bunch of checks which determine the value of a bool var "successful" here
Entity1 e1 = new Entity1;
Entity2 e2 = new Entity2;
//set attributes of the entities
em.persist(e1);
em.persist(e2);
if(successful) em.getTransaction().commit(); else
em.getTransaction().rollback();
If I proceed like so, an exception is thrown when committing:
Query: InsertObjectQuery(banking.Entity2[ id=21 ])
Exception in thread "AWT-EventQueue-0" javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: insert or update on table "Entity2" violates foreign key constraint "Entity2_fk"
Detail: Key (id)=(21) is not present in table "Entity1".
Error Code: 0
Call: INSERT INTO Entity2 (id, attr2, attr3) VALUES (?, ?, ?)
bind => [3 parameters bound]
This message says that Key (id)=(21) is not present in table "Entity1", even though it should be from the first persist. Is this because this is inside a transaction? How do I get around this?
Also, the call INSERT INTO Entity2 (id, attr2, attr3) VALUES (?, ?, ?) is incorrect, as the values have been set.
In short, what is the best way to persist two different entities with FK constraints in a single transaction?
The relevant parts of the entity classes:
public class Entity1 implements Serializable {
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#OneToOne(cascade = CascadeType.ALL, mappedBy = "Entity1 ")
private Entity2 entity2;
}
public class Entity2 implements Serializable {
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#JoinColumn(name = "id", referencedColumnName = "id", insertable = false, updatable = false)
#OneToOne(optional = false)
private Entity2 entity2 ;
}
I am learning JPA with hibernate these days. I am not able to understand why hibernate gives error for a Bidirectional OnetoMany relationship if mappedBy attribute is not specified. Following is the code on which I am getting error:
#Entity
public class Item {
#Id
private long id;
private String name;
private String description;
#OneToMany()
Set<Bid> bids = new HashSet<Bid>();
Bid is the child entity of ITEM
#Entity(name="BIDS")
public class Bid {
#Id
#Column(name="BID_ID")
private Long id;
private Double amount;
#ManyToOne
#JoinColumn(name="ITEM_ID")
Item item;
In the main class I am saving both parent and child entities:
Transaction transaction = session.beginTransaction();
Item item = new Item();
item.setId(111);
item.setDescription("ITEM Description");
item.setName("Name1");
Bid bid = new Bid();
bid.setId(21l);
bid.setAmount(1.1);
bid.setItem(item);
Set<Bid> bids = new HashSet<Bid>();
bids.add(bid);
item.setBids(bids);
session.save(item);
session.save(bid);
transaction.commit();
But hibernate tries to execute following queries and throws excetion that ITEM_BIDS table do not exist.
Hibernate: insert into Item (description, name, id) values (?, ?, ?)
Hibernate: insert into BIDS (amount, ITEM_ID, BID_ID) values (?, ?, ?)
Hibernate: insert into Item_BIDS (Item_id, bids_BID_ID) values (?, ?)
Please tell me why hibernate is generating extra query and how mappedBy element will solve this.
Because if you don't specify mappedBy, you're not saying that the OneToMany between Item and Bid and the ManyToOne between Bid and Item are actually the two sides of a unique bidirectional association.
So Hibernate considers that they are two, different, unidirectional associations. And since the default mapping for a OneToMany association is to use a join table, that's what Hibernate uses.
Inspection Entity:
#Entity
#Table(name="INSPECTION")
public class Inspection implements Serializable
{
...
#OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, orphanRemoval=true)
#OrderColumn(name="LIST_INDEX", nullable=false)
#JoinColumn(name="INSPECTION_ID")
private List<RecommendationInstance> recommendations;
...
}
RecommendationInstance Entity
#Entity
#Table(name = "RECOMMENDATION_INSTANCE")
public class RecommendationInstance implements Serializable
{
#SequenceGenerator(name="RECOMMENDATION_INST_SEQ_GEN", sequenceName="RECOMMENDATION_INST_SEQ", allocationSize=1, initialValue=100)
#Id #GeneratedValue(generator="RECOMMENDATION_INST_SEQ_GEN", strategy=GenerationType.SEQUENCE)
private Long id;
#Column(name="INSPECTION_ID")
private Long inspectionId;
#ManyToOne
#JoinColumn(name="RECOMMENDATION_ID")
private Recommendation recommendation;
#Column(name="DESCRIPTION")
private String description;
...
}
And the table is created as follows:
CREATE TABLE "RECOMMENDATION_INSTANCE"
( "ID" NUMBER(19,0) NOT NULL,
"INSPECTION_ID" NUMBER(19,0) NOT NULL,
"RECOMMENDATION_ID" NUMBER(19,0) NOT NULL,
"DESCRIPTION" VARCHAR2(4000 BYTE) NOT NULL,
"LIST_INDEX" NUMBER(4,0) NOT NULL
) ;
When a new RecommendationInstance is created and I attempt to save the InspectionEntity I get the following error:
Caused by: org.eclipse.persistence.exceptions.DatabaseException:
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: NOT NULL check constraint; SYS_CT_10161 table: "RECOMMENDATION_INSTANCE" column: "LIST_INDEX"
Error Code: -10
Call: INSERT INTO RECOMMENDATION_INSTANCE (ID, DESCRIPTION, INSPECTION_ID, RECOMMENDATION_ID) VALUES (?, ?, ?, ?)
bind => [102, Sprinkler System DESCRIPTION, 110, 40]
Am I missing some relationship here? It looks as though the list_index is being ignored completely.
To give further information, if needed, I did have this working using a join table. However I am doing a refactor since the join table is not needed. This moved the LIST_INDEX column from the join table to the RecommendationInstance table.
I have done this before but using the #OrderBy annotation, for instance, an piece of code I wrote recently:
#OneToMany(mappedBy = "product")
#OrderBy("createdDateTime ASC")
private Collection<SkuUpc> skuUpcs;
Where SkuUpc has a fied
#Column(name = "created_dt")
private Date createdDateTime = new Timestamp(new Date().getTime());
I found that when I removed the NOT NULL constraint then everything worked (duh), but I decided I can deal with that for now. Looking at the logs, JPA first inserts the row without the list_index (thus the constraint violation) then immediately after runs an update to set the list_index.
This answer really creates a more specific question as to why it doesn't set the list_index upon insertion of the row, even when I specify nullable=false
I asked the more specific question here: Why does JPA update the OrderColumn instead of setting it on creation?
Here is my code. I would like to generate an automatic ID based on parent class. I'm using a method to create Airport, so my ID it's coming with is a null value. ID in AirportModel will be generated, but I don't know how to make it in child class.
#Entity(name = "Airport")
#Table(name = "ai_airport")
public class AirportModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "airport_id")
private List<AirportTranslatedModel> translations;
Second class(child):
#Entity(name = "AirportTranslated")
#IdClass(AirportTranslatedModelKey.class)
#Table(name = "ai_translated_airport")
public class AirportTranslatedModel
#Id
#Column(name="airport_id")
private Long airportId;
#Id
#Column(name="language_code", length=2)
private String languageCode;
Third one(keys):
#Embeddable
public class AirportTranslatedModelKey implements Serializable {
#Column(name="airport_id")
private Long airportId;
#Column(name="language_code", length=2)
private String languageCode;
I still got the same errors; log:
Hibernate: insert into ai_airport (active, airport_code, city_code, country_code, externa
l_id, is_default, latitude, longitude, market_code, min_connection_time_DD, min_connection_time_DI, min_connection_time_id, min_connection_time_II, time_diff, VERSION) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into ai_translated_airport (airport_long_name, airport_short_name, airp
ort_id, language_code) values (?, ?, ?, ?)
ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Column 'airport_id' cannot be null
Your current setup has the AirportTranslatedModel airport_id field mapped through a Long- you will need to set the airportId manually to have it set the id in the database. This will likely require that you persist AirportModel and possibly flush to have its PK assigned and available prior to making the AirportModel->AirportTranslatedModel association, so that you can then set the AirportTranslatedModel.airportId.
JPA 2 though allows derived Ids. If you want AirportTranslatedModel to have its ID assigned from AirportModel, it needs to have a relationship to it. There is a simple example at http://wiki.eclipse.org/EclipseLink/Examples/JPA/2.0/DerivedIdentifiers
If you were to model your classes in a similar fashion, it might look like:
public class AirportModel {
..
#OneToMany(mappedby="airportModel", cascade = CascadeType.ALL, orphanRemoval = true)
private List<AirportTranslatedModel> translations;
..
}
public class AirportTranslatedModel {
#Id
#JoinColumn(name="airport_id")
private AirportModel airportModel;
#Id
#Column(name="language_code", length=2)
private String languageCode;
..
}
public class AirportTranslatedModelKey implements Serializable {
private Long airportModel;
private String languageCode;
}
Notice that there is no need to make the AirportTranslatedModelKey and embeddable if you are just using it as a pk class. Also note that the AirportTranslatedModelKey contains a Long airportModel - this must match the type of the pk in the AirportModel, and the name of the relationship property in AirportTranslatedModel.
This will allow AirportTranslatedModel to pull the airport_id value from AirportModel and use it as its PK even though it might not have been generated yet when both entities are still new.