Hibernate Envers - Field 'setordinal' doesn't have a default value from hibernate envers - spring

When inserting the CheckList entity hibernate fails with the following error:
SQL Error: 1364, SQLState: HY000
Field 'setordinal' doesn't have a default value
My Entity structure is as follows:
I have a Embeddable class :
#Embeddable
public class RelateTo {
#Column(length = 100, nullable = false)
private String entityType;
#ElementCollection(fetch = FetchType.LAZY)
#MapKeyColumn(name="name", length = 100)
#Column(name="value", length = 500)
private Map<String, String> properties;
public String getEntityType() {
return entityType;
}
public void setEntityType(String entityType) {
this.entityType = entityType;
}
public Map<String, String> getProperties() {
if(properties == null) {
properties = new HashMap<>();
}
return properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
}
And this class is used within CheckList class as follows:
#Entity
#Audited
public class CheckList {
#ElementCollection(fetch = FetchType.LAZY)
#Fetch(FetchMode.SELECT)
#BatchSize(size = 20)
#OrderColumn
private Set<CheckListItem> items;
#Embedded
private RelateTo relateTo;
public CheckList() {
}
public Set<CheckListItem> getItems() {
if (this.items == null) {
this.items = new HashSet<>();
}
return items;
}
public void setItems(Set<CheckListItem> items) {
this.items = items;
}
public RelateTo getRelateTo() {
return relateTo;
}
public void setRelateTo(RelateTo relateTo) {
this.relateTo = relateTo;
}
}
Hibernate generates audit table for CheckList with reference to RelateTo entity (which contains Map<String,String> called properties) as follows :
CREATE TABLE `check_list_properties_audit` (
`revision_id` int NOT NULL,
`revision_type` tinyint NOT NULL,
`check_list_id` varchar(36) NOT NULL,
`setordinal` int NOT NULL,
`name` varchar(64) NOT NULL,
`value` varchar(128) NOT NULL,
PRIMARY KEY (`revision_id`,`check_list_id`,`value`,`name`),
CONSTRAINT `FKmny3johxwt0i5sfkblq6unicx` FOREIGN KEY (`revision_id`) REFERENCES `revinfo` (`rev`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
Note that the table has a field called 'setordinal' but the field value is not populated during the insert. Here is the trace I got from insert call:
insert into check_list_properties_audit (revision_type, revision_id, check_list_id, value, name) values (?, ?, ?, ?, ?)
--- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [0]
--- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [INTEGER] - [3]
--- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [VARCHAR] - [f5fae3ff-c4f4-4466-8355-b52597b973fd]
--- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [4] as [VARCHAR] - [Some name here]
--- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [5] as [VARCHAR] - [taskName]
There are 6 fields to be inserted but the binding shows only 5 fields are populated. Thus the insert fails.
How can I get rid of this problem. The only option I've right now is to makr it #NotAudited, which I don't want to do.

Related

Spring Data Jdbc and Oracle21c

for my latest assignment I'm developing a Spring boot application which will connect with an Oracle 21c database.
The feature of the oracle release we're interested in is the native JSON data type called OSON (reference here: Oracle 21c JSON data type )
I've developed an old fashion DAO approach to accomplish the task, but I would like to use Spring Data JDBC project for the data access layer ideally with minimal extra configuration.
Actually I'm struggling with the mapping of the columns where the OSON type will be stored. After several tries I've obtained the error below following the idea of creating a custom converter for the datatype.
Any suggestion on how to proceed?
pom:
<!-- ORACLE -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11-production</artifactId>
<version>21.1.0.0</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
Entity class:
#Table("T_BUDGET")
#Data #NoArgsConstructor
public class BudgetEntityData {
#Id
private Long id;
#Column("BUDGET")
private JsonObjectWrapper budget;
}
Wrapper used for the converter:
#Data
public class JsonObjectWrapper {
private OracleJsonValue json;
}
Jdbc configuration with custom converter:
#Configuration
#EnableJdbcRepositories
public class JdbcConfig extends AbstractJdbcConfiguration {
//utility object used to centralize the use of OracleJsonFactory, not involved in the problem
private static OracleJsonFactoryWrapper factoryWrapper = new OracleJsonFactoryWrapper(new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false),
new OracleJsonFactory());
#Override
public JdbcCustomConversions jdbcCustomConversions() {
return new JdbcCustomConversions(Arrays.asList(StringToJsonObjectWrapper.INSTANCE,JsonObjectWrapperToString.INSTANCE));
}
#WritingConverter
enum JsonObjectWrapperToString implements Converter<JsonObjectWrapper, String> {
INSTANCE;
#Override
public String convert(JsonObjectWrapper source) {
return source.toString();
}
}
#ReadingConverter
enum StringToJsonObjectWrapper implements Converter<String, JsonObjectWrapper> {
INSTANCE;
#Override
public JsonObjectWrapper convert(String source) {
JsonObjectWrapper jsonObjectWrapper = new JsonObjectWrapper();
OracleJsonValue osonObject = factoryWrapper.createOsonObject(source);
jsonObjectWrapper.setJson(osonObject);
return jsonObjectWrapper;
}
}
}
Error:
2022-04-07 09:47:27.335 DEBUG 24220 --- [nio-8080-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query
2022-04-07 09:47:27.335 DEBUG 24220 --- [nio-8080-exec-1] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT "T_BUDGET"."ID" AS "ID", "T_BUDGET"."BUDGET" AS "BUDGET" FROM "T_BUDGET"]
2022-04-07 09:48:58.006 ERROR 24220 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.data.mapping.MappingException: Could not read value BUDGET from result set!] with root cause
java.sql.SQLException: Invalid column type: getOracleObject not
implemented for class oracle.jdbc.driver.T4CJsonAccessor at
oracle.jdbc.driver.GeneratedAccessor.getOracleObject(GeneratedAccessor.java:1221)
~[ojdbc11-21.1.0.0.jar:21.1.0.0.0] at
oracle.jdbc.driver.JsonAccessor.getObject(JsonAccessor.java:200)
~[ojdbc11-21.1.0.0.jar:21.1.0.0.0] at
oracle.jdbc.driver.GeneratedStatement.getObject(GeneratedStatement.java:196)
~[ojdbc11-21.1.0.0.jar:21.1.0.0.0] at
oracle.jdbc.driver.GeneratedScrollableResultSet.getObject(GeneratedScrollableResultSet.java:334)
~[ojdbc11-21.1.0.0.jar:21.1.0.0.0] at
com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java)
~[HikariCP-3.4.5.jar:na] at
org.springframework.jdbc.support.JdbcUtils.getResultSetValue(JdbcUtils.java:283)
~[spring-jdbc-5.3.8.jar:5.3.8]
I had the very same issue. I fixed it with the RowMapper like this:
Create DTO for the JSON content (JsonObjectWrapper in your case)
#Getter
#Setter
public class JsonContent {
private String code;
private String name;
}
Create entity (BudgetEntityData in your case)
#Data
#Relation( collectionRelation = "persons" )
public class Person {
#Id
private Long id;
private JsonContent content;
}
Create custom RowMapper (probably JdbcConfig in your case)
public class PersonMapper implements RowMapper<Person> {
static ObjectMapper objectMapper = new ObjectMapper();
#Override
public Person mapRow( ResultSet rs, int rowNum ) throws SQLException {
try {
var jsonContent = rs.getBytes( 2 );
var content = objectMapper.readValue( jsonContent, JsonContent.class );
var person = new Person();
person.setId( rs.getLong( 1 ) );
person.setContent( content );
return person;
} catch ( IOException e ) {
throw new RuntimeException( "JSON unmarschalling failed!", e );
}
}
}
Use it in repository (not mentioned in your case) as
#Repository
public interface PersonRepository extends CrudRepository<Person, Long> {
#Query( value = "SELECT id, ctnt FROM PERSON", rowMapperClass = PersonMapper.class )
#Override
List<Person> findAll();
}
Note: you can even simplify it with the spring-data-jpa as:
Define entity
#Entity
#Table( name = Person.TABLE_NAME )
#Data
#Relation( collectionRelation = "persons" )
public class Person {
static final String TABLE_NAME = "PERSON";
#Id
#GeneratedValue
private Long id;
#Column( name = "CTNT" )
#Convert( converter = JsonContentConverter.class )
private JsonContent content;
}
And the converter
public class JsonContentConverter implements AttributeConverter<JsonContent, byte[]> {
static ObjectMapper objectMapper = new ObjectMapper();
#Override
public byte[] convertToDatabaseColumn( JsonContent attribute ) {
try {
return objectMapper.writeValueAsBytes( attribute );
} catch ( JsonProcessingException e ) {
throw new RuntimeException( "JSON marschalling failed!", e );
}
}
#Override
public JsonContent convertToEntityAttribute( byte[] jsonContent ) {
try {
return objectMapper.readValue( jsonContent, JsonContent.class );
} catch ( IOException e ) {
throw new RuntimeException( "JSON unmarschalling failed!", e );
}
}
}

WebFlux functional endpoint, how to return a ServerResponse with retrieved data and no unnecessary block/wait?

I am totally new to reactive code and after a number of tutorials and youtube videos I am trying to setup a tiny test application using functional endpoints; a simple RouterFunction, RouterHandler and Repository. The problem is how to return an object in the ServerResponse from the respository to the caller, without causing any unnecessary blocking?
I am using Postman for testing. Here's the interesting parts of my test application:
#Configuration
public class BookRouter {
#Autowired
BookRepositoryImpl bookRepository;
#Bean
public RouterFunction<ServerResponse> bookRoutes() {
BookHandler bookHandler = new BookHandler(bookRepository);
return RouterFunctions
.nest(path("/api/books"),
route(GET("/{group}/{name}").and(accept(ALL)), bookHandler::getBook)
);
}
}
#Repository
public class BookRepositoryImpl implements BookRepository {
private final ReactiveMongoTemplate mongoTemplate;
#Autowired
public BookRepositoryImpl(ReactiveMongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
#Override
public Mono<Book> findByName(String group, String name) {
Query query = new Query(Criteria.where("group").is(group).and("name").is(name));
return mongoTemplate.findOne(query, Book.class);
}
}
public class BookHandler {
public Mono<ServerResponse> getBook(ServerRequest request) {
String group = request.pathVariable("group");
String name = request.pathVariable("name");
bookRepository
.findByName(group, name)
.subscribe(
ok -> System.out.println("findByName " + ok),
error -> System.err.println("Error: " + error));
return ServerResponse
.accepted()
.contentType(MediaType.TEXT_PLAIN)
.bodyValue("Request queued");
}
}
When I have the code as shown above, the expected data is printed out in subscribe(ok -> ...), but I haven't figured out how to return this data in the ServerResponse.
If I change the code in getBook() to
return setting
.flatMap(s -> ServerResponse
.ok()
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(s))
.switchIfEmpty(NOT_FOUND);
the returned bodyValue is empty, although I can see that it was retrieved from the database.
Any advice on what I am missing is most appreciated.
Update
I am using MongoDB Compass to view and verify the content of the database.
Debug logging is enabled in application.properties with logging.level.root=DEBUGso the Spring classes write some info in the terminal window. Parts of the somewhat anonymized log is as follows:
2020-09-05 21:37:02.688 DEBUG 32720 --- [ctor-http-nio-3] o.s.w.r.f.s.s.RouterFunctionMapping : [96ef6152-1] Mapped to com.sample.book.BookRouter$$Lambda$586/0x0000000800540040#3b0bf8e0
2020-09-05 21:37:02.717 DEBUG 32720 --- [ctor-http-nio-3] o.s.d.m.core.ReactiveMongoTemplate : findOne using query: { "group" : "Thriller", "name" : "The Shining"} fields: Document{{}} for class: class com.sample.book.Book in collection: book
2020-09-05 21:37:02.734 DEBUG 32720 --- [ctor-http-nio-3] o.s.d.m.core.ReactiveMongoTemplate : findOne using query: { "group" : "Thriller", "name" : "The Shining"} fields: {} in db.collection: book.book
2020-09-05 21:37:02.751 DEBUG 32720 --- [ctor-http-nio-3] org.mongodb.driver.protocol.command : Sending command '{"find": "book", "filter": {"group": "Thriller", "name": "The Shining"}, "limit": 1, "singleBatch": true, "$db": "book"}' with request id 7 to database book on connection [connectionId{localValue:2, serverValue:217}] to server localhost:27017
2020-09-05 21:37:02.766 DEBUG 32720 --- [ntLoopGroup-3-2] org.mongodb.driver.protocol.command : Execution of command with request id 7 completed successfully in 16.24 ms on connection [connectionId{localValue:2, serverValue:217}] to server localhost:27017
2020-09-05 21:37:02.837 DEBUG 32720 --- [ntLoopGroup-3-2] o.s.http.codec.json.Jackson2JsonEncoder : [96ef6152-1] Encoding [_id=5f53692af0a02d3af8a7fed9, group=Thriller, name=The Shining, value=in]]
2020-09-05 21:37:02.853 DEBUG 32720 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations : [id: 0x96ef6152, L:/0:0:0:0:0:0:0:1:8088 - R:/0:0:0:0:0:0:0:1:50248] Decreasing pending responses, now 0
2020-09-05 21:37:02.879 DEBUG 32720 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter : [96ef6152-1] Completed 200 OK
2020-09-05 21:37:02.905 DEBUG 32720 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations : [id: 0x96ef6152, L:/0:0:0:0:0:0:0:1:8088 - R:/0:0:0:0:0:0:0:1:50248] Last HTTP response frame
2020-09-05 21:37:02.931 DEBUG 32720 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations : [id: 0x96ef6152, L:/0:0:0:0:0:0:0:1:8088 - R:/0:0:0:0:0:0:0:1:50248] Last HTTP packet was sent, terminating the channel
I found the problem. I had forgot to implement getters in the Book class holding the #Document. I am surprised that there were no error message or warning when they were missing.
As soon as I inserted them, the result was returned as expected from this code:
return setting
.flatMap(s -> ServerResponse
.ok()
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(s))
.switchIfEmpty(NOT_FOUND);
Here is the data as returned to Postman after the fix:
{
"_id": "5f53692af0a02d3af8a7fed9",
"group": "Thrillers",
"name": "The Shining",
"value": "in"
}
Thank you to #caco3 for helping me find the problem!
Here is my updated Book.java.
#Document
#CompoundIndex(name = "group-name", def = "{'group':1, 'name':1}", unique = true) // Requires auto-index-creation in application.properties
public class Book {
#Id
private String _id;
private String group;
private String name;
private String value;
public Book() {
}
public Book(String group, String name, String value) {
this.group = group;
this.name = name;
this.value = value;
}
#Override
public String toString() {
StringBuilder s = new StringBuilder('[');
s.append("_id=").append(_id);
s.append(", group=").append(group);
s.append(", name=").append(name);
s.append(", value=").append(value);
s.append(']');
return s.toString();
}
public String get_id() {
return _id;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

spring-data-jdbc: query entity containing 1-n relation with JOOQ

I am trying to load entities containing a reference to another entity (1-n) with the help of JOOQ (based on spring-data-jdbc).
I'm started extending the spring-data-jdbc-jooq-example.
The adjusted model with the 1-n relation:
#Data
public class Category {
private #Id Long id;
private String name, description;
private AgeGroup ageGroup;
private Set<SubCategory> subCategories;
public Category() {}
public Category(Long id, String name, String description, AgeGroup ageGroup) {
this(id, name, description, ageGroup, new HashSet<>());
}
public Category(Long id, String name, String description, AgeGroup ageGroup, Set<SubCategory> subCategories) {
this.id = id;
this.name = name;
this.description = description;
this.ageGroup = ageGroup;
this.subCategories = subCategories;
}
}
#Data
#AllArgsConstructor
#NoArgsConstructor
public class SubCategory {
private #Id Long id;
private String title;
}
I wrote two queries, one via the #Query-Annotation in the CrudRepository and one with the help of JOOQ in the JooqRepository.
interface CategoryRepository extends CrudRepository<Category, Long>, JooqRepository {
#Query("SELECT * FROM category")
List<Category> findAllWithQuery();
}
public interface JooqRepository {
List<Category> findAllWithJooq();
}
public class JooqRepositoryImpl implements JooqRepository {
private final DSLContext dslContext;
public JooqRepositoryImpl(DSLContext dslContext) {
this.dslContext = dslContext;
}
#Override
public List<Category> findAllWithJooq() {
return dslContext.select()
.from(CATEGORY)
.fetchInto(Category.class);
}
}
(for me both methods should return the same result-set b/c they execute the same query?!)
But my unit-test fails:
#Test
public void exerciseRepositoryForSimpleEntity() {
// create some categories
SubCategory sub0 = new SubCategory(null, "sub0");
SubCategory sub1 = new SubCategory(null, "sub1");
Category cars = new Category(null, "Cars", "Anything that has approximately 4 wheels", AgeGroup._3to8, Sets.newLinkedHashSet(sub0, sub1));
// save category
repository.saveAll(asList(cars));
// execute
List<Category> actual = repository.findAllWithJooq();
List<Category> compare = repository.findAllWithQuery();
Output.list(actual, "JOOQ");
Output.list(compare, "Query");
// verify
assertThat(actual).as("same size of categories").hasSize(compare.size());
assertThat(actual.get(0).getSubCategories()).as("same size of sub-categories").hasSize(compare.get(0).getSubCategories().size());
}
with
java.lang.AssertionError: [same size of sub-categories]
Expecting actual not to be null
As you can see in the following output the sub-categories queried by JOOQ will not be loaded:
2019-11-26 16:28:00.749 INFO 18882 --- [ main] example.springdata.jdbc.jooq.Output : ==== JOOQ ====
Category(id=1,
name=Cars,
description=Anything that has approximately 4 wheels,
ageGroup=_3to8,
subCategories=null)
2019-11-26 16:28:00.749 INFO 18882 --- [ main] example.springdata.jdbc.jooq.Output : ==== Query ====
Category(id=1,
name=Cars,
description=Anything that has approximately 4 wheels,
ageGroup=_3to8,
subCategories=[SubCategory(id=1,
title=sub0),
SubCategory(id=2,
title=sub1)])
This is the used database-shema:
CREATE TABLE IF NOT EXISTS category (
id INTEGER IDENTITY PRIMARY KEY,
name VARCHAR(100),
description VARCHAR(2000),
age_group VARCHAR(20)
);
CREATE TABLE IF NOT EXISTS sub_category (
id INTEGER IDENTITY PRIMARY KEY,
title VARCHAR(100),
category INTEGER
)
In the JOOQ variant, JOOQ does the conversion from ResultSet to object instances. Since JOOQ doesn't know about the interpretation of aggregates as it is done by Spring Data JDBC it only hydrates the Category itself, not the contained Set of SubCategory.
Spring Data JDBC on the other hand interprets the structure of the Category and based on that executes another statement to load the subcategories.

hibernate error: java.sql.BatchUpdateException: ORA-00932: inconsistent datatypes: expected NUMBER got BINARY

I am trying to insert a row into a table called Mstrauthorizations. When doing so, I get an error saying Could not execute JDBC batch update. The row is not in the DB - so - I do not see how it could be updating anything at all. The database being used is Oracle. When doing the insert, the keyid is generated with the help of Oracle sequences. My understanding is that the auto-increment of key ids (primary key) is not possible until Oracle 12c. The Mstrauthorizations.java code was generated using Hibernate.
Update: made changes to the Mstrauthorizations.java file and am now getting the following error: java.sql.BatchUpdateException: ORA-00932: inconsistent datatypes: expected NUMBER got BINARY I have initialized the attribuetes/fields of the table in the Mstrauthorizations.java file (so no null values would be passed in) but this is not working.
How can I at least see the column that the hibernate command is complaining about? I am trying to do an insert. Why is an update being performed?
log information
1323 [main] DEBUG org.hibernate.transaction.JDBCTransaction - current autocommit status: false
1327 [main] DEBUG org.hibernate.event.def.AbstractSaveEventListener - generated identifier: 0, using strategy: org.hibernate.id.Assigned
1347 [main] DEBUG org.hibernate.transaction.JDBCTransaction - commit
1348 [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - processing flush-time cascades
1349 [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - dirty checking collections
1350 [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - Flushed: 1 insertions, 0 updates, 0 deletions to 1 objects
1350 [main] DEBUG org.hibernate.event.def.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
1351 [main] DEBUG org.hibernate.pretty.Printer - listing entities:
1351 [main] DEBUG org.hibernate.pretty.Printer - com.apostx.tables.Mstrauthorizations{employeeid=0, lastlogints=0, reclockts=2007-09-23 10:10:10.0, authorizationsid=0, memo=no value, logonid=joney#mitchell.com, lastname=Mitchell, firstname=Joney, logonpassword=1234567, archived=0, reclockpid=3434, reclockhost=no host, reclocktype=6, active=0, tenantid=5, worktype=0, reclockid=999999}
1368 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
1373 [main] DEBUG org.hibernate.SQL - insert into ORAAPPS.MSTRAUTHORIZATIONS (ACTIVE, ARCHIVED, EMPLOYEEID, FIRSTNAME, LASTLOGINTS, LASTNAME, LOGONID, LOGONPASSWORD, MEMO, RECLOCKHOST, RECLOCKID, RECLOCKPID, RECLOCKTS, RECLOCKTYPE, TENANTID, WORKTYPE, AUTHORIZATIONSID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1482 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1
1496 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
1498 [main] DEBUG org.hibernate.util.JDBCExceptionReporter - Could not execute JDBC batch update [insert into ORAAPPS.MSTRAUTHORIZATIONS (ACTIVE, ARCHIVED, EMPLOYEEID, FIRSTNAME, LASTLOGINTS, LASTNAME, LOGONID, LOGONPASSWORD, MEMO, RECLOCKHOST, RECLOCKID, RECLOCKPID, RECLOCKTS, RECLOCKTYPE, TENANTID, WORKTYPE, AUTHORIZATIONSID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]
java.sql.BatchUpdateException: ORA-00932: inconsistent datatypes: expected NUMBER got BINARY
at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10656)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at com.apostx.hibernate.soverflow.test.TestStack.main(TestStack.java:32)
1498 [main] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 932, SQLState: 42000
1498 [main] ERROR org.hibernate.util.JDBCExceptionReporter - ORA-00932: inconsistent datatypes: expected NUMBER got BINARY
1498 [main] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 932, SQLState: 42000
1498 [main] ERROR org.hibernate.util.JDBCExceptionReporter - ORA-00932: inconsistent datatypes: expected NUMBER got BINARY
1499 [main] ERROR org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session
org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92)
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:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at com.apostx.hibernate.soverflow.test.TestStack.main(TestStack.java:32)
Caused by: java.sql.BatchUpdateException: ORA-00932: inconsistent datatypes: expected NUMBER got BINARY
at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10656)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 8 more
Exception in thread "main" org.hibernate.exception.SQLGrammarException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92)
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:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at com.apostx.hibernate.soverflow.test.TestStack.main(TestStack.java:32)
Caused by: java.sql.BatchUpdateException: ORA-00932: inconsistent datatypes: expected NUMBER got BINARY
at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10656)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 8 more
TIA
Main program - dbconnection test - working
package com.apostx.dbconnection.test;
import java.sql.*;
public class TestDBConnection {
public static void main(String[] args) {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con=DriverManager.getConnection("jdbc:oracle:thin:#scar:1527:DSV", "ora787", "Huiu7ti" );
Statement statement = con.createStatement();
String sql = "select * from MstrAuthorizations";
ResultSet rs = statement.executeQuery(sql);
while (rs.next()) {
System.out.println("first col " + rs.getInt(1) + " second col " + rs.getString(2));
System.out.println( "login id is " + rs.getString("logonid"));
}
con.close();
}
catch ( Exception e ) {
System.out.println("Database Connection Testing Error : " + e);
e.printStackTrace();
}
}
}
Main Program : Not working
package com.apostx.hibernate.test;
import java.math.BigDecimal;
import org.apache.log4j.BasicConfigurator;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.apostx.tables.Mstrauthorizations;
public class AddRecord {
public static void main(String[] args) {
BasicConfigurator.configure();
// create session factory
SessionFactory factory = new Configuration().
configure("hibernate.cfg.xml").
addAnnotatedClass(Mstrauthorizations.class).
buildSessionFactory();
// create session
Session session = factory.getCurrentSession();
try {
// create object
System.out.println("about to start the work ....");
Mstrauthorizations mstr = new Mstrauthorizations();
BigDecimal tenantid=new BigDecimal(5);
mstr.setFirstname("Joney"); mstr.setLastname("Mitchell");
mstr.setTenantid(tenantid);mstr.setLogonid("joney#mitchell.com");
mstr.setLogonpassword("1234567");mstr.setReclockid(new BigDecimal(999999));
mstr.setReclockhost("no host");mstr.setReclockpid(new BigDecimal(3434));
mstr.setReclocktype(new BigDecimal(6));
// start transaction
session.beginTransaction();
// save info
System.out.println("about to save the data ...");
session.save(mstr);
// commit transaction
session.getTransaction().commit();
System.out.println("All Saved ...");
}
catch ( Exception e ) {
System.out.println("error message is " + e.getLocalizedMessage());
}
finally {
factory.close();
}
}
}
Mstrauthorizations.java
package com.apostx.tables;
// Generated Jun 22, 2017 9:30:03 PM by Hibernate Tools 4.0.0
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
/**
* Mstrauthorizations generated by hbm2java
*/
#Entity
#Table(name = "MSTRAUTHORIZATIONS", schema = "ORAAPPS", uniqueConstraints = {
#UniqueConstraint(columnNames = { "TENANTID", "LOGONID" }),
#UniqueConstraint(columnNames = { "TENANTID", "EMPLOYEEID" }) })
public class Mstrauthorizations {
private BigDecimal authorizationsid = new BigDecimal(0);
private BigDecimal tenantid = new BigDecimal(0);
private BigDecimal employeeid = new BigDecimal(0);
private String logonid = new String("no value");
private String logonpassword = new String("no value");
private BigDecimal worktype = new BigDecimal(0);
private BigDecimal lastlogints = new BigDecimal(0);
private String memo = new String("no value");
private String firstname = new String("no value");
private String lastname = new String("no value");
private BigDecimal active = new BigDecimal(0);
private BigDecimal archived = new BigDecimal(0);
private BigDecimal reclocktype = new BigDecimal(0);
private BigDecimal reclockid = new BigDecimal(0);
private String reclockhost = new String("no value");
private BigDecimal reclockpid = new BigDecimal(0);
private Timestamp reclockts = java.sql.Timestamp.valueOf("2007-09-23 10:10:10.0");
public Mstrauthorizations() {
}
public Mstrauthorizations(BigDecimal authorizationsid) {
this.authorizationsid = authorizationsid;
}
public Mstrauthorizations(BigDecimal authorizationsid, BigDecimal tenantid,
BigDecimal employeeid, String logonid, String logonpassword,
BigDecimal worktype, BigDecimal lastlogints, String memo,
String firstname, String lastname, BigDecimal active,
BigDecimal archived, BigDecimal reclocktype, BigDecimal reclockid,
String reclockhost, BigDecimal reclockpid, Timestamp reclockts) {
this.authorizationsid = authorizationsid;
this.tenantid = tenantid;
this.employeeid = employeeid;
this.logonid = logonid;
this.logonpassword = logonpassword;
this.worktype = worktype;
this.lastlogints = lastlogints;
this.memo = memo;
this.firstname = firstname;
this.lastname = lastname;
this.active = active;
this.archived = archived;
this.reclocktype = reclocktype;
this.reclockid = reclockid;
this.reclockhost = reclockhost;
this.reclockpid = reclockpid;
this.reclockts = reclockts;
}
#Id
#Column(name = "AUTHORIZATIONSID", unique = true, nullable = false, precision = 22, scale = 0)
public BigDecimal getAuthorizationsid() {
return this.authorizationsid;
}
public void setAuthorizationsid(BigDecimal authorizationsid) {
this.authorizationsid = authorizationsid;
}
#Column(name = "TENANTID", precision = 22, scale = 0)
public BigDecimal getTenantid() {
return this.tenantid;
}
public void setTenantid(BigDecimal tenantid) {
this.tenantid = tenantid;
}
#Column(name = "EMPLOYEEID", precision = 22, scale = 0)
public BigDecimal getEmployeeid() {
return this.employeeid;
}
public void setEmployeeid(BigDecimal employeeid) {
this.employeeid = employeeid;
}
#Column(name = "LOGONID", length = 60)
public String getLogonid() {
return this.logonid;
}
public void setLogonid(String logonid) {
this.logonid = logonid;
}
#Column(name = "LOGONPASSWORD", length = 40)
public String getLogonpassword() {
return this.logonpassword;
}
public void setLogonpassword(String logonpassword) {
this.logonpassword = logonpassword;
}
#Column(name = "WORKTYPE", precision = 22, scale = 0)
public BigDecimal getWorktype() {
return this.worktype;
}
public void setWorktype(BigDecimal worktype) {
this.worktype = worktype;
}
#Column(name = "LASTLOGINTS", precision = 22, scale = 0)
public BigDecimal getLastlogints() {
return this.lastlogints;
}
public void setLastlogints(BigDecimal lastlogints) {
this.lastlogints = lastlogints;
}
#Column(name = "MEMO", length = 100)
public String getMemo() {
return this.memo;
}
public void setMemo(String memo) {
this.memo = memo;
}
#Column(name = "FIRSTNAME", length = 30)
public String getFirstname() {
return this.firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
#Column(name = "LASTNAME", length = 30)
public String getLastname() {
return this.lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
#Column(name = "ACTIVE", precision = 22, scale = 0)
public BigDecimal getActive() {
return this.active;
}
public void setActive(BigDecimal active) {
this.active = active;
}
#Column(name = "ARCHIVED", precision = 22, scale = 0)
public BigDecimal getArchived() {
return this.archived;
}
public void setArchived(BigDecimal archived) {
this.archived = archived;
}
#Column(name = "RECLOCKTYPE", precision = 22, scale = 0)
public BigDecimal getReclocktype() {
return this.reclocktype;
}
public void setReclocktype(BigDecimal reclocktype) {
this.reclocktype = reclocktype;
}
#Column(name = "RECLOCKID", precision = 22, scale = 0)
public BigDecimal getReclockid() {
return this.reclockid;
}
public void setReclockid(BigDecimal reclockid) {
this.reclockid = reclockid;
}
#Column(name = "RECLOCKHOST", length = 80)
public String getReclockhost() {
return this.reclockhost;
}
public void setReclockhost(String reclockhost) {
this.reclockhost = reclockhost;
}
#Column(name = "RECLOCKPID", precision = 22, scale = 0)
public BigDecimal getReclockpid() {
return this.reclockpid;
}
public void setReclockpid(BigDecimal reclockpid) {
this.reclockpid = reclockpid;
}
#Column(name = "RECLOCKTS")
public Serializable getReclockts() {
return this.reclockts;
}
public void setReclockts(Timestamp reclockts) {
this.reclockts = reclockts;
}
}
Fixed when following this:
Hibernate: Where do insertable = false, updatable = false belong in composite primary key constellations involving foreign keys?
When data saved to table, ID generated on DB side. Just set "insertable" and "updatable" to false for ID and Timestamp.

Converter doesn't work and not taken by criteria

i'm new here^^
i'm working with a db in which boolean are registered as VARCHAR(3) So i made a converter :
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
#Converter
public class BooleanToStringConverter implements
AttributeConverter<Boolean, String> {
#Override
public String convertToDatabaseColumn(Boolean value) {
if (value == null)
return "";
else if (value)
return "OUI";
else
return "NON";
}
#Override
public Boolean convertToEntityAttribute(String value) {
if (value == null)
return null;
else if (value.trim().equals("OUI"))
return true;
else if (value.trim().equals("NON"))
return false;
else if (value.trim().equals(""))
return null;
else
throw new IllegalStateException("Invalid boolean character: "
+ value);
}
}
i put my annotations #Convert:
public class Institution extends AbstractHREntity {
#Column(name = "IDOU00")
private String code;
#Column(table = "ZEXX", name = "LBOULG")
private String libelle;
#Column(table = "ZEXX", name = "LBOUSH")
private String abreviation;
#Column(table = "ZEYY", name = "LIBEXL")
private String libelleLong;
#Convert(converter = BooleanToStringConverter.class)
#Column(table = "ZEZZ", name = "ESTBUDGET", length = 3)
private Boolean isBudget;[/CODE]
But when i do a request with a criteria :
public List<Institution> findInstitutions(RechercheInstitutionData datas) throws DaoException{
List<Institution> resultList = new ArrayList<Institution>();
DetachedCriteria criteria = DetachedCriteria.forClass(Institution.class, "institution");
if(null!=datas.getInstitutionSearched())
{
if (StringUtils.isNotBlank(datas.getInstitutionSearched().getLibelleLong())){
criteria.add(Restrictions.like("institution.libelleLong", datas.getInstitutionSearched().getLibelleLong().toUpperCase(), MatchMode.START));
}
if (StringUtils.isNotBlank(datas.getInstitutionSearched().getAbreviation())){
criteria.add(Restrictions.like("institution.abreviation", datas.getInstitutionSearched().getAbreviation().toUpperCase(), MatchMode.START));
}
if (StringUtils.isNotBlank(datas.getInstitutionSearched().getLibelle())){
criteria.add(Restrictions.like("institution.libelle", datas.getInstitutionSearched().getLibelle(), MatchMode.START).ignoreCase());
}
if (StringUtils.isNotBlank(datas.getInstitutionSearched().getCode())){
criteria.add(Restrictions.like("institution.code", datas.getInstitutionSearched().getCode(), MatchMode.START));
}
criteria.addOrder(Order.asc("institution.code"));
}
resultList = find(criteria);
return resultList;
}
i had this error that occurred :
10:25:31,172 INFO [RechercheInstitution.beans.RechercheInstitutionBean] (http-localhost/127.0.0.1:8080-5) --> findInstitutions()
10:25:32,549 INFO [stdout] (http-localhost/127.0.0.1:8080-5) Hibernate: select this_.NUDOSS as NUDOSS1_35_0_, this_.IDOU00 as IDOU2_35_0_, this_1_.TBUDGE as TBUDGE1_39_0_, this_2_.LIBEXL as LIBEXL1_37_0_, this_3_.LBOUSH as LBOUSH1_36_0_, this_3_.LBOULG as LBOULG2_36_0_ from ZE00 this_ left outer join ZEWD this_1_ on this_.NUDOSS=this_1_.NUDOSS left outer join ZE04 this_2_ on this_.NUDOSS=this_2_.NUDOSS left outer join ZE01 this_3_ on this_.NUDOSS=this_3_.NUDOSS where this_3_.LBOUSH like ? order by this_.IDOU00 asc
10:25:33,310 WARN [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http-localhost/127.0.0.1:8080-5) SQL Error: -99999, SQLState: 07006
10:25:33,311 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http-localhost/127.0.0.1:8080-5) Data type mismatch. (For input string: "OUI")
10:25:33,313 ERROR [RechercheInstitution.ejb.institution.InstitutionMgrBean] (http-localhost/127.0.0.1:8080-5) InstitutionMgrBean.findInstitutions : common_HR.exception.DaoException: org.hibernate.exception.SQLGrammarException: could not execute query
10:25:33,315 INFO [RechercheInstitution.beans.RechercheInstitutionBean] (http-localhost/127.0.0.1:8080-5) <-- findInstitutions()
It looks like it doesn't use my converter, i tried breakpoints it doesn't go into my converter... In converter doc it says "all you have to do is put the #convert" but apparently no... Please help i'm really lost.

Resources