Grails: Db row update fails silently when domain class contains 'version false' - mysql

I'm using grails v3.2.9
I have a domain class Offer containing
static mapping = {
version false
}
I insert a row to a offer table, then in another transaction I try to update a value of one column inside that row, but offer update silently fails while other entities in the same transaction are updated properly.
I save the offer as follows:
offer.save(failOnError: true)
so it is not the case of offer.save() when the validation fails and saving fails silently.
However if I add version column to offer table(dbCreate is set to none) and change the Offer domain class to contain
static mapping = {
version true
}
the row starts to be updated successfully.
When I inspect the audit_log for offer table there is only the insertion events, no any update event is there.
It is very weird as I have other domain classes containing version = false and updating there works fine.
Any help would be appreciated.

Since version = false, the property Offer.version is equal to null and the column does not exist in database. Normally when you perform updates Hibernate will automatically check the version property against the version column in the database. So, I am just guessing it may be a bug with the hibernate session trying check a value that is null. I tried to replicate your scenario but I did not succeed.
Have you tried flushing the session when you save?:
offer.save(flush: true, failOnError: true)

It is also possible that when you changed the domain that required version to a domain that doesn't require version, the underlying database table didn't drop that column.
By default the version column is created as NOT NULL in the physical database. Even though hibernate doesn't care about the version property in the domain, the physical database won't let that record inserted and hence it fails.
While this explains why a record is not inserted, it doesn't explain why it doesn't throw an error. It shouldn't fail silently and instead throw a SQL exception.

Related

Kafka connect jdbc sink upsert mode issue

I'm trying to connect replicate a table at realtime using Kafka connect. The database used is MySQLv5.7.
On working with insert and update mode separately, the columns are behaving as expected. However, when I use the upsert mode, no change is observed in the database.
Configuration File filled via UI
Sink
topic = custom-p2p
Connector Class = JdbcSinkConnector
name = sink
tasks-max = 1
Key-converter-class=org.apache.kafka.connect.storage.StringConverter
Value-converter-class=org.apache.kafka.connect.json.JsonConverter
jdbc_url=jdbc:mysql://127.0.0.1:3306/p2p_service_db4?user=root&password=root&useSSL=false
insert mode = upsert
auto create = true
auto evolve = true
Source
Connector Class = JdbcSourceConnector
name = source-new
task max = 1
key converter class = org.apache.kafka.connect.storage.StringConverter
value converter class = org.apache.kafka.connect.json.JsonConverter
jdbc url = jdbc:mysql://127.0.0.1:3306/p2p_service_db3?user=root&password=root&useSSL=false
table loading mode = timestamp+incrementing
incrementing column name = auto_id
timestamp column name = last_updated_at
topic prefix = custom-
ver
The issue that I'm having is that when the sink insert mode is changed to insert, the insertion takes place properly when changed to update, this also happens perfectly as expected, however when the value is changed to upsert, neither insertion nor update takes place.
Please let me know if something done is wrong? Why this mode is not working? Is there some alternative to this if this inserts and updates both need to be replicated in the backup DB.
Thank you in advance. Let me know if some other information is needed

FindBy columnName when column name contains "Id"

In Grails, Gorm, I have this entity:
class MyEntity implements Serializable {
Long bankTransactionId
int version
BigDecimal someValue
static constraints = {
bankTransactionId(nullable: false)
version(nullable: true)
someValue(nullable: true)
}
}
Doing MyEntity.findByBankTransactionId(Long.valueOf("3")) throws this exception:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown
column 'this_.id' in 'field list'
I am suspecting the fact that my column has the name id in it. Could it be this?
How to fix it then ?
Thanks.
Everything you have provided here looks fine. In particular, there are no restrictions about having the letters "id" in a column name.
Take a look at your generated MySQL table. I'm guessing that the id column isn't there for some reason. Maybe something prevented generating it due to some earlier error that you have now corrected, or you have your datasource set to "none" instead of "update" (or similar) and the whole table is missing!
If this is just a development environment with no real data (and no foreign key constraints), drop the whole MyEntity table and let it be automatically recreated. If not, move to a different temporary datasource, let a new table be created, and compare the two. If the new one still doesn't have an id column, you have something going wrong during your startup that is preventing your tables from being created correctly. You could just add the column in manually, but if you don't figure out what happened to it in the first place, it will probably just happen again.
For reference, in my test environment, my MySQL table for "MyEntity" copied from your example looks like:
desc my_entity;
'id','bigint(20)','NO','PRI',NULL,'auto_increment'
'version','int(11)','YES','',NULL,''
'bank_transaction_id','bigint(20)','NO','',NULL,''
'some_value','decimal(19,2)','YES','',NULL,''

IllegalStateException while trying create NativeQuery with EntityManager

I have been getting this annoying exception while trying to create a native query with my entity manager. The full error message is:
java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: com.model.OneToManyEntity2#61f3b3b.
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.discoverUnregisteredNewObjects(RepeatableWriteUnitOfWork.java:313)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.calculateChanges(UnitOfWorkImpl.java:723)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.writeChanges(RepeatableWriteUnitOfWork.java:441)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:874)
at org.eclipse.persistence.internal.jpa.QueryImpl.performPreQueryFlush(QueryImpl.java:967)
at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:207)
at org.eclipse.persistence.internal.jpa.QueryImpl.getSingleResult(QueryImpl.java:521)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.getSingleResult(EJBQueryImpl.java:400)
The actual code that triggers the error is:
Query query;
query = entityManager.createNativeQuery(
"SELECT MAX(CAST(SUBSTRING_INDEX(RecordID,'-',-1) as Decimal)) FROM `QueriedEntityTable`");
String recordID = (query.getSingleResult() == null ?
null :
query.getSingleResult()
.toString());
This is being executed with an EntityTransaction in the doTransaction part. The part that is getting me with this though is that this is the first code to be executed within the doTransaction method, simplified below to:
updateOneToManyEntity1();
updateOneToManyEntity2();
entityManager.merge(parentEntity);
The entity it has a problem with "OneToManyEntity1" isn't even the table I'm trying to create the query on. I'm not doing any persist or merge up until this point either, so I'm also not sure what is supposedly causing it to be out of sync. The only database work that's being done up until this code is executed is just pulling in data, not changing anything. The foreign keys are properly set up in the database.
I'm able to get rid of this error by doing as it says and marking these relationships as Cascade.PERSIST, but then I get a MySQLContrainstraViolationException on the query.getSingleResult() line. My logs show that its doing some INSERT queries right before this, so it looks like its reaching the EntityManager.merge part of my doTransaction method, but the error and call stack point to a completely different part of the code.
Using EclipseLink (2.6.1), Glassfish 4, and MySQL. The entitymanager is using RESOURCE_LOCAL with all the necessary classes listed under the persistence-unit tag and exclude-unlisted-classes is set to false.
Edit: So some more info as I'm trying to work through this. If I put a breakpoint at the beginning of the transaction and then execute entityManager.clear() through IntelliJ's "Evaluate Expression" tool, everything works fine at least the first time through. Without it, I get an error as it tries to insert empty objects into the table.
Edit #2: I converted the nativeQuery part into using the Criteria API and this let me actually make it through my code so I could find where it was unintentionally adding in a null object to my entity list. I'm still just confused as to why the entity manager is caching these errors or something to the point that creating a native query is breaking because its still trying to insert bad data. Is this something I'd need to call EntityManager.clear() before doing each time? Or am I supposed to call this when there is an error in the doTransaction method?
So after reworking the code and setting this aside, I stumbled on at least part of the answer to my question. My issue was caused by the object being persisted prior to the transaction starting. So when I was entering my transaction, it first tried to insert/update data from my entity objects and threw an error since I hadn't set the values of most of the non-null columns. I believe this is the reason I was getting the cascade errors and I'm positive this is the source of the random insert queries I saw being fired off at the beginning of my transaction. Hope this helps someone else avoid a lot of trouble.

How to ignore case using breeze FilterQueryOp

I am using breeze to query data from the server and seem to be running into problems.
Is there a way to filter this data and ignore cases or making the value from the field a lower case?
Example:
var term = "john";
query = query.where("Name", "contains", Term);
The problem I am having is if the 'Name' field contains John with capital 'J', It return false but returns true if I change term to 'John'.
I know this is case issue but how can I make breeze ignore the casing? without using jquery.each.
Thanks. Any help will be greatly appreciated.
In my opinion there is a simpler approach to this.
By default OData is case sensitive, but nonetheless provides functions to transform a string to lower or upper case. So to fire a case-insensitive query to the server simply modify your code as follows:
var term = "john";
query = query.where("tolower(Name)", breeze.FilterQueryOp.Contains, term.toLowerCase());
Thus OData is told to transform the subject to lower case before comparing it to your search string, which has been converted to lower case before sending it to the server.
Ok, there are two parts to this. Breeze supports a LocalQueryComparisonOptions object that is used for all localQueries.
var lqco = new breeze.LocalQueryComparisonOptions({
name: "custom comparison options",
isCaseSensitive: false,
usesSql92CompliantStringComparison: true
});
// either apply it globally
lqco.setAsDefault();
// or to a specific MetadataStore
var ms = new breeze.MetadataStore({ localQueryComparisonOptions: lqco });
var em = new breeze.EntityManager( { metadataStore: ms });
You should set this once at the beginning of your application. In this example, all localQueries performed after this point will be case insensitive.
The problem is that unless your database is ALSO set to "match" these settings ( performing this differs by database vendor), then remote queries against the server will return different results then the same query applied locally.
Basically, Breeze cannot set the "server" side implementation, so the recommendation is usually to create a localQueryComparisons object that matches your server side database settings.
Hope this makes sense.
If anyone run into this problem on an Oracle DB, I added the code above from Jay Traband then modified a logon trigger to alter session variables for DB users.
Set the following values:
ALTER SESSION SET nls_comp = linguistic;
ALTER SESSION SET nls_sort = binary_ci
Hope this helps someone out. I love Breeze!!!

changing rewriteBatchedStatements with play, hibernate and mysql

I'm trying to optimize for bulk inserts via play(1.2.4)+mysql.
I saw some posts talking about adding the following to jdbc configuration (adding it to the connection string): useServerPrepStmts=false&rewriteBatchedStatements=true&useCompression=true
I've tried to do:
db=mysql://root#localhost/data?useServerPrepStmts=false&rewriteBatchedStatements=true&useCompression=true
But I get this error:
A database error occured : Cannot connected to the database, The connection property 'useCompression' only accepts values of the form: 'true', 'false', 'yes' or 'no'. The value 'true?useUnicode=yes' is not in this set.
I also tried to use db=jdbc:mysql://....
Still no luck.
What am I missing?
Play automatically appends the MySQL connection string with the following:
?useUnicode=yes&characterEncoding=UTF-8&connectionCollation=utf8_general_ci
So I am guessing your connection string ends up invalid as there is now two sets of parameters (starting with a question mark).
Unfortunately, that part of Play code is quite hard-coded in the DBPlugin class which means that you can't add the options that way. You will have to look for a way to alter the options in a later stage.