IllegalStateException while trying create NativeQuery with EntityManager - mysql

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.

Related

Delphi: Cannot perform this operation on an open dataset

When I tried to use FireDAC FDQuery with MySQL database I got the following error:
Cannot perform this operation on an open dataset.
query.Open(....my connection string to MySQL....);
try
query.ExecSql;
finally
query.Close;
I filled the FDQuery by double-clicking on the icon on the form. I also
connected to the database to test it. It gave back the results correctly.
I would like to use it from code, but it doesn't work, so
I debugged it. I always get to the breakpoint: query.Close;
You can't call Open and ExecSQL on the same SQL, because they do different things.
Use Open when the query will return a result set, which means for a SELECT. Use ExecSQL when the query does not return a result set, which means for an INSERT, DELETE or UPDATE.
I can't tell you which one applies to your situation, because you failed to include your SQL in your post.
I don't know about FireDAC specifically, but in general with these kind of database components, for queries not returning a result set, thus suitable for ExecSQL, you would want to use ExecSQL on the Connection object, in this case TFDConnection. (Which would presumably be the Connection object that your FDQuery object is connected to.)
http://docwiki.embarcadero.com/RADStudio/Rio/en/Executing_Commands_(FireDAC)
Apparently there is an ExecSQL method on TFDCustomQuery, but I'm not sure why you would use that, and as you discovered, it doesn't work if the query is already in use.

Why won't truncateTable work in Joomla 3.7?

I have the following code attempting to truncate a table. The Joomla documentation makes me believe this will work, but it does not. What am I missing?
$db = JFactory::getDbo();
truncate_query = $db->getQuery(true);
//$truncate_query = 'TRUNCATE ' . $db->quoteName('#__mytable');
$truncate_query->truncateTable($db->quoteName('#__mytable'));
$db->setQuery($truncate_query);
echo $truncate_query;
exit();
If I use the line that is commented out to manually generate the SQL, it does work. The reason I am still looking to use the truncateTable function is that I am trying to include the truncation in a transaction. When I use the manual statement, the table is still truncated even if another part of the transaction fails, which is annoying since the other statements rely on data that is truncated, so if the table is emptied when it shouldn't be there is no data left to run the transaction again. Very annoying!
Here's how you call/execute your truncation query:
JFactory::getDbo()->truncateTable('#__mytable');
And now some more details...
Here is the method's code block in the Joomla source code:
public function truncateTable($table)
{
$this->setQuery('TRUNCATE TABLE ' . $this->quoteName($table));
$this->execute();
}
As you can see the truncateTable() method expects a tablename as a string for its sole parameter; you are offering a backtick-wrapped string -- but the method already offers the backtick-wrapping service. (Even if you strip your backticks off, your approach will not be successful.)
The setQuery() and execute() calls are already inside the method, so you don't need to create a new query object nor execute anything manually.
There is no return in the method, so the default null is returned -- ergo, your $truncate_query becomes null. When you try to execute(null), you get nothing -- not even an error message.
If you want to know how many rows were removed, you will need to run a SELECT query before hand to count the rows.
If you want to be sure that there are no remaining rows of data, you'll need to call a SELECT and check for zero rows of data.
Here is my answer (with different wording) on your JSX question.

Calling MySQL stored procedure in ROR 4

There are few example out there but non of them are very clarified (or on old version).
I want to call MySQL procedure and check the return status (in rails 4.2). The most common method I saw is to call result = ActiveRecord::Base.connection.execute("call example_proc()"), but in some places people wrote there is prepared method result = ActiveRecord::Base.connection.execute_procedure("Stored Procedure Name", arg1, arg2) (however it didn't compiled).
So what is the correct way to call and get the status for MySQL procedure?
Edit:
And how to send parameters safly, where the first parameter is integer, second string and third boolean?
Rails 4 ActiveRecord::Base doesn't support execute_procedure method, though result = ActiveRecord::Base.connection still works. ie
result = ActiveRecord::Base.connection.execute("call example_proc('#{arg1}','#{arg2}')")
You can try Vishnu approach below
or
You can also try
ActiveRecord::Base.connections.exec_query("call example_proc('#{arg1}','#{arg2}')")
here is the document
In general, you should be able to call stored procedures in a regular where or select method for a given model:
YourModel.where("YOUR_PROC(?, ?)", var1, var2)
As for your comment "Bottom line I want the most correct approach with procedure validation afterwards (for warnings and errors)", I guess it always depends on what you actually want to implement and how readable you want your code to be.
For example, if you want to return rows of YourModel attributes, then it probably would be better if you use the above statement with where method. On the other hand, if you write some sql adapter then you might want to go down to the ActiveRecord::Base.connection.execute level.
BTW, there is something about stored proc performance that should be mentioned here. In several databases, database does stored proc optimization on the first run of the stored proc. However, the parameters that you pass to that first run might not be those that will be running on it more frequently later on. As a result, your stored-proc might be auto-optimized in a "none-optimal" way for your case. It may or may not happen this way, but it is something that you should consider while using stored procs with dynamic params.
I believe you have tried many other solutions and got some or other errors mostly "out of sync" or "closed connection" errors. These errors occur every SECOND time you try to execute the queries. We need to workaround like the connection is new every time to overcome this. Here is my solution that didn't throw any errors.
#checkout a connection for Model
conn = ModelName.connection_pool.checkout
#use the new connection to execute the query
#records = conn.execute("call proc_name('params')")
#checkout the connection
ModelName.connection_pool.checkin(conn)
The other approaches failed for me, possibly because ActiveRecord connections are automatically handled to checkout and checking for each thread. When our method tries to checkout a connection just to execute the SP, it might conflict since there will be an active connection just when the method started.
So the idea is to manually #checkout a connection for the model instead of for thread/function from the pool and #checkin once the work is done. This worked great for me.

T-SQL Clear Errors

I'm trying to clean up a huge legacy T-SQL stored proc. We call it from BizTalk. BizTalk has a feature to retry a send port (for example 3 times every 5 minutes) when it is in error.
For example, the stored proc detects missing data and does this:
if #CompanyID is null raiserror( '#CompanyID is missing', 18, 1 );
The "Begin Catch" logic handles certain errors, (i.e. logs them to error tables), and then does a "Return 0". I believe the prior programmer thought this would keep BizTalk from calling it again. But now I have a trace and I can prove that BizTalk is calling it x retries every y minutes apart (as defined by the BizTalk SendPort).
My current thought is that if ##Error and ##ErrorMessage are not null, BizTalk still thinks it is in error, and will retry.
Any thoughts on how to totally clear the errors? I was hoping to do a small quick fix, no time for a major rewrite.
This may not be applicable but if you increase the error level this may fix the issue by causing a more serious error to be logged. Generally 1 through 19 I believe are more informational related and after 20 is considered a fatal error and will log the error in the SQL Log as well. This may force the program to stop even if a handler is still believing it to be open. You may always test this and see if it suits your needs and change it back if not. You may also try a more proper BEGIN END blocking too and a generic return not returning a value for the catchs like:
IF #CompanyID is NULL
BEGIN
Raiserror('#CompanyID is missing', 20, 1);
return;
END
More on error catching here: http://msdn.microsoft.com/en-us/library/ms178592.aspx
If the error handling is SQL-based then it sounds like you may want to replace your RAISERROR completely and instead log your error at that point and simply return.
Also, ##Error will never be null. It will return a "new" value with each statement that is executed. If the previous statement is executed successfully, it will return 0, otherwise it will return the error number....which in your case would be 18. If your logic is keying off of ##Error, then you need to make sure it is being checked (or saved into a variable) immediately after the statement in question executes.
More info below.
http://technet.microsoft.com/en-us/library/ms190193(v=sql.100).aspx
I think this post basically answers my question (this is also a post by me to zoom into clarification relating to error handling inside a catch block):
T-SQL is error handling totally turned off in a "BEGIN CATCH" block?
Certain statements in a try catch do not blow up. They can set the error and the code keeps on falling through.
In this specific case, the catch block had an Insert into a table, and one column had been expanded in the stored proc, but not in the error table. We expanded the column in other tables probably 4 months ago, but we never caught this insidious hidden issue with the error handler until this week.
I think that the other StackOverflow post will eventually help answer the question as to why BizTalk see this as an error. I would think "return 0" would do it. But since we were getting the truncation problem, that error was being sent to BizTalk.
In the real world, we rarely hit this error code, and when we do, the the particular column that was causing the error was not too big. This error arose when a QA person began a certain test scenario and was putting in some invalid flight numbers in conjunction with a particularly long value for the offending column.

LINQ problems with NText, Text and Image on SQL server

Apologies up front, because this isn't a question but a solution - but it took a lot of searching to find out the answer and google wasn't much help, so I wanted to give something back to the community by providing the error and the solution to help future googlers.
When using LINQ to SQL, I ran into a problem when submitting changes (the second time) to a data table. The first time I submit changes all is OK, the second time I submit changes I recieved a SQL exception which said:
"The text, ntext, and image data types cannot be compared or sorted,
except when using IS NULL or LIKE operator"
The exception was thrown when I was calling SubmitChanges(), but because of the lazy loading of LINQ it actually arose in the previous line when I was calling Refresh(RefreshMode.KeepCurrentValues, myObject).
The problem is that the Refresh mode is attempting to compare the current with the database version of all the fields, and SQL doesn't support that kind of comparison text, ntext and image columns (at least not on SQL Server 2000).
The solution is to add the following attribute to your column definition
UpdateCheck = UpdateCheck.Never
e.g.
[Column(DbType = "NText", CanBeNull = true, UpdateCheck = UpdateCheck.Never)]
Then the Refresh mode works OK and SubmitChanges doesn't have any further problems.