Eclipselink JPA gets error when inserting into Derby table with generated primary key - jpa

EclipseLink seems to be incorrectly passing a null primary key value to Derby when persisting into a table with generated primary key. Derby returns error of Attempt to modify an identity column in this case. Derby needs a SQL statement that excludes the id value. My question is how do I coerce EclipseLink to send the right SQL? Details follow...
I am using Eclipselink to map to a Derby database (v10.8.1.2) under the latest Netbeans 7.3beta2.
The database table primary key is auto generated:
CREATE TABLE STUDENT_BATCH (
ID bigint PRIMARY KEY
GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
FILENAME varchar(200) NOT NULL,
SCHOOLBOARD varchar(100) NOT NULL,
CREATE_TS timestamp NOT NULL,
CONTACT_INFO varchar(200),
NOTES varchar(2000),
BOARD_NAME varchar(100)
)
;
The corresponding jpa class specifies that the id is generated using strategy of identity:
#Entity
#Table(name = "STUDENT_BATCH")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "StudentBatch.findAll", query = "SELECT s FROM StudentBatch s")})
public class StudentBatch implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private Long id;
#Basic(optional = false)
#Column(name = "FILENAME")
private String filename;
#Basic(optional = false)
#Column(name = "SCHOOLBOARD")
private String schoolboard;
#Basic(optional = false)
#Column(name = "CREATE_TS")
#Temporal(TemporalType.TIMESTAMP)
private Date createTs;
#Column(name = "CONTACT_INFO")
private String contactInfo;
#Column(name = "NOTES")
private String notes;
#Column(name = "BOARD_NAME")
private String boardName;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "studentBatchId")
private Collection<StudentRecord> studentRecordCollection;
methods etc follow...
When I go to persist the class, I do not specify an id so that Derby will provide the id.
StudentBatch sb = new StudentBatch();
sb.setBoardName(meta.get("BOARD NAME"));
sb.setContactInfo(meta.get("CONTACT INFO"));
sb.setCreateTs(new Date());
sb.setFilename(event.getFile().getFileName());
sb.setNotes(meta.get("NOTES"));
sb.setSchoolboard(meta.get("SCHOOL BOARD"));
_logger.debug("persisting batch");
em.persist(sb);
_logger.debug("flushing");
em.flush();
_logger.debug("flushed");
Eclipselink, however, passes the id to derby as null and Derby gives error Attempt to modify an identity column:
INFO: DEBUG 11710 27 Nov 2012 18:17:10,558 [http-thread-pool-8080(4)] (FileUploadController.java:75) - persisting batch
INFO: DEBUG 11713 27 Nov 2012 18:17:10,561 [http-thread-pool-8080(4)] (FileUploadController.java:77) - flushing
WARNING: Local Exception Stack:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: Attempt to modify an identity column 'ID'.
Error Code: -1
Call: INSERT INTO STUDENT_BATCH (ID, BOARD_NAME, CONTACT_INFO, CREATE_TS, FILENAME, NOTES, SCHOOLBOARD) VALUES (?, ?, ?, ?, ?, ?, ?)
bind => [7 parameters bound]
Query: InsertObjectQuery(ca.ontario.mhltc.studentupload.model.StudentBatch[ id=null ])
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:333)
This makes some sense to me since if I try to execute an insert on sql command line with the id field specified I get an error too.
INSERT INTO STUDENT_BATCH (id, BOARD_NAME, CONTACT_INFO, CREATE_TS, FILENAME, NOTES, SCHOOLBOARD)
VALUES (null, 'abc', 'def', current_timestamp, 'aaa', 'aabb', '1234');
gives me this:
Error code -1, SQL state 42Z23: Attempt to modify an identity column 'ID'.
Line 1, column 1
Execution finished after 0 s, 1 error(s) occurred.
however, this insert statement is successful:
INSERT INTO STUDENT_BATCH (BOARD_NAME, CONTACT_INFO, CREATE_TS, FILENAME, NOTES, SCHOOLBOARD)
VALUES ('abc', 'def', current_timestamp, 'aaa', 'aabb', '1234');
returns
Executed successfully in 0.002 s, 1 rows affected.
Line 1, column 1
Execution finished after 0.002 s, 0 error(s) occurred.
Seems to me that Eclipselink should know about how Derby handles identity columns and should not pass the id column at all on the insert statement. Is there a workaround for this or I should I just dump Derby and use some other database?

EclipseLink does not include the Id in the INSERT for Derby IDENTITY, so you have something odd going on.
Did you previously use another generator strategy and not recompile/deploy your code correctly?
Also try setting your platform using the"eclipselink.target-database"="Derby" in your persistence.xml.

Related

Numeric types mapping issue in Spring Data R2dbc with postgres

I tried to use Spring Data R2dbc/Postgres in a sample application.
Spring Boot 2.4.0-M2
R2dbc Postgres (managed by Spring Boot)
Spring Data R2dbc 1.2.0-M2(managed by Spring Boot)
The table scripts.
CREATE SEQUENCE IF NOT EXISTS ORDERS_ID_SEQ;
CREATE TABLE IF NOT EXISTS ORDERS(
ID INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('ORDERS_ID_SEQ') ,
CUST_ID BIGINT NOT NULL,
AMOUNT REAL NOT NULL
);
ALTER SEQUENCE ORDERS_ID_SEQ OWNED BY ORDERS.ID;
The data.sql:
-- INSERT SAMPLE DATA
DELETE FROM ORDERS;
INSERT INTO ORDERS(CUST_ID, AMOUNT) VALUES (1, 100.2);
I use a ResourceDatabasePopulator to populate the data, it works.
But when I was trying to save the data by Repository, failed.
#Table(value = "ORDERS")
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Order implements Serializable {
#Id
#Column(value = "ID")
private Integer id;
#Column(value = "CUST_ID")
private Long customerId;
// use BigDecimal or Java Money API in the real-world application.
#Column(value = "AMOUNT")
private Double amount;
}
public interface OrderRepository extends R2dbcRepository<Order,Integer> {
}
// in application runner.
orders .save(Order.builder().customerId(c.getId()).amount(201.0).build())
It threw an exception like this:
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.UnsupportedOperationException: Binding parameters is not supported for the statement 'INSERT INTO ORDERS (CUST_ID, AMOUNT) VALUES (?, ?)'
Caused by: java.lang.UnsupportedOperationException: Binding parameters is not supported for the statement 'INSERT INTO ORDERS (CUST_ID, AMOUNT) VALUES (?, ?)'
at io.r2dbc.postgresql.SimpleQueryPostgresqlStatement.bind(SimpleQueryPostgresqlStatement.java:78) ~[r2dbc-postgresql-0.8.4.RELEASE.jar:0.8.4.RELEASE]
at io.r2dbc.postgresql.SimpleQueryPostgresqlStatement.bind(SimpleQueryPostgresqlStatement.java:44) ~[r2dbc-postgresql-0.8.4.RELEASE.jar:0.8.4.RELEASE]
The complete codes is here.
Updated: Give up extending from AbstractR2dbcConfiguration, and get resovled when following the official guide.

Hibernate postgres auto increment after manual insert

I have a basic spring application, with a simple entity. I have a flyway script, to create the postgres table, and add some starting data.
create table user (
id serial primary key,
username varchar (50) unique not null,
password varchar (150) not null
);
insert into user (id, username, password) values (1, 'name', 'somehashed');
insert into etc...
I've set up my entity as follows:
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", updatable = false, columnDefinition = "serial")
private Long id;
...
other fields, constructor, getters setters etc...
My problem is, that on start-up, the basic entities are persisted by flyway, but upon trying to save a new entity, hibernate tries to give it the ID 1, although it is already given to another one.
I tried it also with SEQUENCE strategy, the problem didn't get solved.
Ok, problem was that I specified explicitly the ID I wanted to give while the insert script, and I didn't let postgres do the magic...

Error in Sequence lookup in Hibernate for Postgresql

I am having problem in inserting data into Postgresql through Hibernate when Primary column has auto-increment.
I have gone through multiple post in this forum also, but can't find a solution that works for me.
My Table and Sequence are defined in "apiprofile" schema. When I run the code, it is unable to find the Sequence name.
Even if I mention it with the schema.sequence, still it doesn't work.
Any help is appreciated.
Below are the code snippet and exception I am facing.
Sequence & Table:
CREATE SEQUENCE apiprofile.login_session_id_seq;
CREATE TABLE apiprofile.login_session (
id bigint NOT NULL DEFAULT nextval('apiprofile.login_session_id_seq'),
username varchar(255) NOT NULL,
token varchar(500) NOT NULL,
active_ind boolean NOT NULL,
login_time timestamp NOT NULL,
PRIMARY KEY (id)
);
Bean file
public class LoginSession {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "session_generator")
#SequenceGenerator(name="session_generator", sequenceName = "apiprofile.login_session_id_seq", schema = "apiprofile", allocationSize=1)
#Column(name="id", updatable = false, nullable = false)
private Integer id;
Insert operation
LoginSession session = new LoginSession();
session.setUsername(userName);
session.setToken(token);
session.setActive(true);
session.setLoginTime(new Timestamp(System.currentTimeMillis()));
getSession().saveOrUpdate(session);
Exception
Hibernate:
select
next_val as id_val
from
login_session_id_seq for update
could not read a hi value
org.postgresql.util.PSQLException: ERROR: relation "login_session_id_seq" does not exist
Position: 32
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2103) ~[postgresql-9.1-901-1.jdbc4.jar:?]
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1836) ~[postgresql-9.1-901-1.jdbc4.jar:?]
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257) ~[postgresql-9.1-901-1.jdbc4.jar:?]

JPQL Query working in testing, not in production

I have two Entities related by a ManyToMany and I want to select them via a named Query. This works in my test (with a H2 DB set up) and throws exceptions at runtime (with postgresql set up). Other than the H2 and PG I am hard pressed to find differences between test and production.
The Entities and the Query look like so (abbreviated):
#Entity(name = "Enrichment")
#Table(name = "mh_Enrichment")
NamedQueries({
#NamedQuery(name = "findByLink",
query = "SELECT e FROM Enrichment e INNER JOIN e.links l WHERE l.link in (:links)") })
public class EnrichmentImpl {
#Id
#Column(name = "enrichmentId")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#ManyToMany
#JoinTable(name = "mh_EnrichmentLinks", joinColumns = { #JoinColumn(name = "EnrichmentId",
referencedColumnName = "enrichmentId") }, inverseJoinColumns = { #JoinColumn(name = "Link",
referencedColumnName = "link") })
private List<Link> links;
}
#Entity(name = "Link")
#Table(name = "mh_enrichment_link")
public class LinksImpl {
#Id
#Column(name = "link", length = 1024)
private String link;
}
Upon running the query with a String value in production I get:
Internal Exception: org.postgresql.util.PSQLException: ERROR: operator does not exist: character varying = bigint
Hinweis: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Position: 215
Error Code: 0
Call: SELECT t1.enrichmentId FROM mh_enrichment_link t0, mh_EnrichmentLinks t2, mh_Enrichment t1 WHERE ((t0.link IN (?)) AND ((t2.EnrichmentId = t1.enrichmentId) AND (t0.link = t2.Link)))
Any ideas what's wrong? It is the query, isn't it?
The query is supposed to retrieve a list of Enrichments that are related to the given link.
Update #1
As requested: the tables in the DB look as follows:
For entity Link
CREATE TABLE mh_enrichment_link
(
link character varying(1024) NOT NULL,
CONSTRAINT mh_enrichment_link_pkey PRIMARY KEY (link)
)
For entity Enrichment
CREATE TABLE mh_enrichment
(
enrichmentid bigint NOT NULL,
CONSTRAINT mh_enrichment_pkey PRIMARY KEY (enrichmentid)
)
For the relation (See answer, this was where it went wrong)
CREATE TABLE mh_enrichmentlinks
(
link character varying(1024) NOT NULL,
CONSTRAINT mh_enrichment_link_pkey PRIMARY KEY (link)
)
The issue was fixed by dropping all related tables and having JPA regenerate them. Table definitions didn't match Entity definitions.
Thats also the quite obviously the reason why the test worked and the production didn't. In testing the tables are generated on runtime, in production they existed already (with an outdated definition).
Side note: The query is correct and does what it should.

Persisting data to database leads to illegal state exception

I have a JPA question.
Let's say I have an entity set up as followed (only a hypothetical).
#Entity
#Table (name = "TESTTABLE")
public class TestTable {
#Id
#Basic (optional = false)
private String id;
#JoinColumn(name="TESTID", referencedColumnName = "ID")
#OneToOne(optional = true)
private TestTable testId;
}
Basically,
--=--=--=---=----
|TestTable....... |
--=--=--=---=----
| String id..........|<-----------------------|
| String testId....|-----------TestId = id |
--=--=--=--=--=-=
I have foreign_key constraints set up in the DB and, codewise, I am expecting the normal "integrity constraint violated - parent key not found" constraint to be returned if the value entered for the testId does not have a corresponding id value in TestTable (so if the only entries I had were (1, null) and (2, 1), (3, 17) would result in failure).
However, when I try to persist an entry such as the forementioned (3, 17) to the database, I get an IllegalStateException error (because I have no CascadeType.PERSIST and I am trying to persist an object that does not exist in the db). I get that this is expected behavior, but is there anyway to bypass this and just let the database handle it (and thus return the expected constraint)?
Thanks.
Just use cascade PERSIST in the relationship.
In EclipseLink you can also use the persistence unit property,
"eclipselink.persistence-context.commit-without-persist-rules"="true"