Why do these Gradle tests throw exceptions? - grails-orm

I've got following test
answer = Author.withCriteria {
books {
gt 'price', new DetachedCriteria(Book).build {
projections {
avg 'price'
}
}
}
}
assert answer.size() == 1
Intellij IDEA executes this test without exceptions. If I run gradle build this test rises org.hibernate.exception.SQLGrammarException: could not execute query exception.
Intellij generates following SQL:
select this_.id as id2_1_, this_.version as version2_1_, this_.age as age2_1_, this_.email as email2_1_, this_.first_name as first5_2_1_, this_.home_page as home6_2_1_, this_.last_name as last7_2_1_, this_.login as login2_1_, this_.salary as salary2_1_, this_.sex as sex2_1_, (SELECT count(*) FROM BOOK b WHERE b.author_id = this_.id) as formula0_1_, books_alia1_.id as id1_0_, books_alia1_.version as version1_0_, books_alia1_.author_id as author3_1_0_, books_alia1_.date_created as date4_1_0_, books_alia1_.last_updated as last5_1_0_, books_alia1_.price as price1_0_, books_alia1_.title as title1_0_ from author this_ inner join book books_alia1_ on this_.id=books_alia1_.author_id where (books_alia1_.price > (select avg(cast(this_.price as double)) as y0_ from book this_))
Gradle SQL:
select this_.id as id2_1_, this_.version as version2_1_, this_.age as age2_1_, this_.email as email2_1_, this_.first_name as first5_2_1_, this_.home_page as home6_2_1_, this_.last_name as last7_2_1_, this_.login as login2_1_, this_.salary as salary2_1_, this_.sex as sex2_1_, (SELECT count(*) FROM BOOK b WHERE b.author_id = this_.id) as formula0_1_, books_alia1_.id as id0_0_, books_alia1_.version as version0_0_, books_alia1_.author_id as author3_0_0_, books_alia1_.date_created as date4_0_0_, books_alia1_.last_updated as last5_0_0_, books_alia1_.price as price0_0_, books_alia1_.title as title0_0_ from author this_ inner join book books_alia1_ on this_.id=books_alia1_.author_id where (books_alia1_.price > (select from book this_)
You can see problems with avg 'price' part.
Question is the same: Why tests executed by Gradle have exceptions?
ps
Intellij dependecies are installed by gradle idea command

Only you can find out. Maybe the class paths are different (remember that IDEA doesn't have as strict a class path separation as Gradle), or the resources are different (again this works differently in IDEA compared to Gradle). First thing to do is to analyze the stack trace. Debugging the test in Gradle (-Dtest.debug=true) can also help.

Related

Jetbrains Exposed SQL HAVING COUNT(*)

I need to achieve this next SQL query using the Exposed framework from Jetbrains
select r.name
from recipes r
inner join ingredient_index i on i.recipe_id = r.recipe_id
where i.ingredient_id IN (7, 5)
GROUP BY r.name
HAVING COUNT(*) = 2
This is taken directly from this answer, and the result from the query in native SQL is exactly what I'm looking for, but I'm using Exposed framework on my backend.
Stackoverflow question
I'm having issues with the last part HAVING COUNT(*) = X
I see there's a method I can use that's query.having { } but I don't see how I could implement the COUNT(*) = X inside that expression.
Any help is appreciated.

Could the Runtime Exception (column list_id does not exist) come from left join?

In my Android Studio project I have implemented a database (managed by Room). In my Dao file, I have the following query which causes an error:
SELECT tab1.list_id, ... FROM
(SELECT list_id, ... FROM list_table) AS tab1
LEFT JOIN
(SELECT list_id, ... FROM list_table NATURAL JOIN product_table NATURAL JOIN list_product_table GROUP BY list_id) AS tab2
ON tab1.list_id = tab2.list_id
ORDER BY list_position ASC, tab1.list_id ASC;
The error says java.lang.IllegalArgumentException: column '`list_id`' does not exist. The error points to the file, which was automatically created by Room.
...
return __db.getInvalidationTracker().createLiveData(new String[]{"list_table","product_table","list_product_table"}, false, new Callable<List<ShoppingListDisplayValues>>() {
#Override
public List<ShoppingListDisplayValues> call() throws Exception {
final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
try {
final int _cursorIndexOfPosition = CursorUtil.getColumnIndexOrThrow(_cursor, "list_position");
final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, "list_id");
...
To be more specific, the error points to the line:
final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, "list_id");
Now my question is, could this error result from the left join? The really weird thing is, that the code works on some devices and on other not. Would be really glad, if someone has an idea.
So, after debugging a couple of hours I found the error and a solution.
Error origin
The error lies in the Room persistence library. When using this library on devices with API lower than 27 (at least this is what I guess, since I tested 3 devices with different APIs), then an exception gets thrown IF you use a table prefix in your SELECT statement. By "table prefix" I mean for example the tab1. in tab1.list_id.
The solution:
Just use an alias for the column which has a table prefix.
Instead of
SELECT tab1.list_id, ... FROM
write
SELECT tab1.list_id AS list_id, ... FROM

Syntax Error - Missing Operator - Cannot determine what is missing

What is wrong with the SQL statement? I get a message that there is a syntax error (missing operator). From the ASSIGNMENT TABLE I am wanting to select all rows where ASSN_TRANS_STATE_NUM = '1'. For each of these rows I then want to get the project name from the PROJECTS table. I also want to get each of the Task names from the TASKS table. I did get this to work earlier (not sure what change I made that broke it) but even when it did work it was not correct. It was reporting every task for each of the projects, instead of just giving me the tasks specific to a project.
SELECT
TRANS.PROJ_UID,
PROJ.PROJ_NAME,
TRANS.TASK_UID,
TASKS.TASK_NAME,
TRANS.ASSN_TRANS_STATE_ENUM,
TRANS.ASSN_TRANS_APPROVER_RES_UID
FROM dbo_MSP_ASSIGNMENT_TRANSACTIONS TRANS
INNER JOIN dbo_MSP_PROJECTS PROJ ON PROJ.PROJ_UID = TRANS.PROJ_UID
INNER JOIN dbo_MSP_TASKS TASKS ON TASKS.TASK_UID = TRANS.TASK_UID
WHERE TRANS.ASSN_TRANS_STATE_ENUM = 1;
It will be dbo. rather than dbo_. I guess it should help
SELECT
TRANS.PROJ_UID,
PROJ.PROJ_NAME,
TRANS.TASK_UID,
TASKS.TASK_NAME,
TRANS.ASSN_TRANS_STATE_ENUM,
TRANS.ASSN_TRANS_APPROVER_RES_UID
FROM dbo.MSP_ASSIGNMENT_TRANSACTIONS TRANS
INNER JOIN dbo.MSP_PROJECTS PROJ ON PROJ.PROJ_UID = TRANS.PROJ_UID
INNER JOIN dbo.MSP_TASKS TASKS ON TASKS.TASK_UID = TRANS.TASK_UID
WHERE TRANS.ASSN_TRANS_STATE_ENUM = 1;

Optimizing a request doing tons of exclusions

I have a huge and dirty SQL request doing many exclusions and I feel bad about it. Perhaps, you know a better way to proceed.
Here's a part of my request:
select name, version, iteration, score
from article, articlemaster
where article.idmaster = articlemaster.id
and article.id not in (select article.id
from article, spsarticlemaster
where article.idmaster = articlemaster.id
and articlemaster.name = 'nameOfMyArticle'
and article.version = 'A'
and article.state = 'CONTINUE')
and article.id not in....
and article.id not in....
You think it doesn't look that bad ? Actually, this is only a portion of the request, the "and spsarticle.id not in ...." exclude one article, and i got more than 1000 to exclude, so i'm using a java program to append the other 999.
Any idea how could i make a light version of this abomination ?
You might be better off loading all of the articles to exclude into a temporary table, then joining that table in to your query.
For example, create exclude_articles:
name version state
---- ------- -----
nameOfMyArticle A CONTINUE
Then exclude its results from the query:
select
article.name,
article.version,
article.iteration,
article.score
from
article
join articlemaster
on article.idmaster = articlemaster.id
where
not exists (
select 1
from article article2
join articlemaster articlemaster2
on article2.idmaster = articlemaster2.id
join exclude_articles
on articlemaster2.name = exclude_articles.name
and article2.version = exclude_articles.version
and article2.state = exclude_articles.state
where article.id = article2.id)
This is all assuming that the version and state are actually necessary for the exclusion logic. It would be a much easier case if the name is unique.
If you're using Java to create the query and process the results, then why not do all the complicated logic in Java? Just ask the database for all the articles matching some basic criterion (or maybe you really do want to read through all of them) and then filter the results:
select am.name, a.version, a.iteration, a.score, a.state
from article a, articlemaster am
where a.idmaster = am.id
and <some other basic criteria>
Then in Java loop over all the results (sorry, my Java is super rusty) and filter out the ones you don't want:
ArrayList recordList = ArrayList();
ArrayList finalList = ArrayList();
for (record in recordList) {
if (! filterThisRecord(record)) {
finalList.append(record);
}
}

nHibernate performance issue when loading large collections

(just to make clear: my app isn't really about employees and departments. I just use these terms for example's sake).
Each department has an employees collection, which is lazily-loaded. Whenever I add a new employee I want to make sure It doesn't already exist in the collection, so I load the collection to memory and perform the check on it.
Problem is- in production environment, I have some departments with 10,000+ employees.
I found that fetching the collection and then saving the new employee takes A LOT of time.
I've done a little experment, in which I copied the exact same select statement generated by nH to ADO.Net SQLDataAdapter. Here are the results:
***16:04:50:437*** DEBUG NHibernate.SQL - SELECT ... FROM dbo.[Employee] emp0_ left outer join dbo.[Department] department1_ on emp0_.Department_id=department1_.Id left outer join dbo.[TableC] TableC2_ on department1_.TableC_id=TableC2_.Id WHERE emp0_.SomeField_id=#p0;#p0 = 2
***16:05:00:250*** DEBUG NHibernate.SQL - SELECT ... FROM dbo.TableD codeshared0_ left outer join dbo.[Department] department1_ on codeshared0_.Department_id=department1_.Id left outer join dbo.[TableC] TableC2_ on department1_.TableC_id=TableC2_.Id WHERE codeshared0_.Employee_id in (select emp0_.Id FROM dbo.[Employee] emp0_ left outer join dbo.[Department] department1_ on emp0_.Department_id=department1_.Id left outer join dbo.[TableC] TableC2_ on department1_.TableC_id=TableC2_.Id WHERE emp0_.SomeField_id=#p0);#p0 = 2
16:05:04:984 DEBUG NHibernate.SQL - Reading high value:select next_hi from dbo._uniqueKey with (updlock, rowlock)
16:05:05:078 DEBUG NHibernate.SQL - Updating high value:update dbo._uniqueKey set next_hi = #p0 where next_hi = #p1;#p0 = 10686, #p1 = 10685
***16:05:05:328*** DEBUG MyApp.Managers - commiting
16:05:12:000 DEBUG NHibernate.SQL - INSERT INTO dbo.[Employee] (...) VALUES (#p0, #p1, #p2, #p3, #p4, #p5, #p6, #p7, #p8, #p9);#p0 = 23/04/2011 04:04:49, #p1 = 23/04/2011 03:34:49, #p2 = 23/04/2011 04:04:49, #p3 = 23/04/2011 03:34:49, #p4 = '', #p5 = False, #p6 = 433, #p7 = NULL, #p8 = 2, #p9 = 10685
16:05:12:140 DEBUG NHibernate.SQL - UPDATE dbo.[Employee] SET Department_id = #p0 WHERE Id = #p1;#p0 = 2, #p1 = 10685
16:05:12:343 DEBUG MyApp.Managers - success
16:05:12:359 DEBUG MyApp.Tests - ------------------------------------------------------------
16:05:12:359 DEBUG MyApp.Tests - Finished nHib stuff- now switching to ADO
16:05:12:359 DEBUG MyApp.Tests - starting SQL: SELECT ... FROM dbo.[Employee] emp0_ left outer join dbo.[Department] department1_ on emp0_.Department_id=department1_.Id left outer join dbo.[TableC] TableC2_ on department1_.TableC_id=TableC2_.Id WHERE emp0_.SomeField_id=2
16:05:14:750 DEBUG MyApp.Tests - total rows received: 10036
16:05:14:750 DEBUG MyApp.Tests - SQL: SELECT ... FROM dbo.TableD codeshared0_ left outer join dbo.[Department] department1_ on codeshared0_.Department_id=department1_.Id left outer join dbo.[TableC] TableC2_ on department1_.TableC_id=TableC2_.Id WHERE codeshared0_.Employee_id in (select emp0_.Id FROM dbo.[Employee] emp0_ left outer join dbo.[Department] department1_ on emp0_.Department_id=department1_.Id left outer join dbo.[TableC] TableC2_ on department1_.TableC_id=TableC2_.Id WHERE emp0_.SomeField_id=2)
16:05:15:250 DEBUG MyApp.Tests - total rows received: 2421
as you can see- fetching takes ~15 secs with nH, compared to ~2 secs with ADO.Net.
From researching around a bit I know that nH probably isn't meant to be used to store that many items in session. Can you think of any other possible reason for this problem, or of another suggestion other than filtering the Employees at the DB level?
thanks
--EDIT--
Following the below suggestions i've tried using Reflection Optimizer (made no difference), and IStatelessSession for loading my collection (throws an exception- collections cannot be fetched by a stateless session.).
I think my code in the Department class will have to change from the clean:
if (this.Employees.Contains(emp))
{
...
}
to this 'dirtier' version:
var employeesRepository = IOCContainer.Get<IEmployeesRepository>();
if (employeesRepository.EmployeeExists(this,emp))
{
...
}
anyone has a better suggestion?
There is no reason for you to load all the empoyees to memory. you should write a query
using HQL/Critiria API/Linq to NHibernate to check if the employee already existing in the DB.
for example:
var existingEmpoyee = session.Query<Employee>()
.Where(e => e.Equals(newEmployee))
.FirstOrDefault();
if(existingEmployee != null)
// Insert new employee to DB
I would use a StatelessSession and batch optimization.
The session will keep track of all the
loaded objects, and if we load a lot
of data, it will eventually blow out
with an out of memory exception.
Luckily, NHibernate has a ready made
solution for this, the stateless
session. The code now looks like this:
using (IStatelessSession s = sessionFactory.OpenStatelessSession())
{
var books = new ActionableList<Book>(book => Console.WriteLine(book.Name));
s.CreateQuery("from Book")
.List(books);
}
The stateless session, unlike the
normal NHibernate session, doesn’t
keep track of loaded objects, so the
code here and the data reader code are
essentially the same thing.
For batch optimization and more: NHibernate performance tricks.
hmmmm. may be its too much, and actually - i'd expect an "lazy=extra" ISet to behave like this, but you can write your own "extra lazy" ISet.
if you didn't encounter an extra lazy collection - its a collection that, for example, when you ask its count, it doesn't fetch everything but issues a count query.
your extra lazy ISet could issue an exists query whenever you try to add something.
If you implement this, your code would be clean and you could submit the code to nhibernate core.
you should however think about add range, and be careful not to issue N queries
good luck.