ColumnNotFound problem with Magic in play scala - java

I'm getting a "play.exceptions.JavaExecutionException:
ColumnNotFound(comments.id)" in a piece of code after trying to
migrate to MySql instead of the memorydb. Postgres support by Magic is
almost null.
The evolution:
create table comments (
id bigint(20) NOT NULL AUTO_INCREMENT,
source varchar(255) NOT NULL,
target varchar(255) NOT NULL,
content text NOT NULL,
date bigint NOT NULL,
PRIMARY KEY (id)
);
The model:
case class comments(id: Pk[Long], source: String, target: String,
content: String, date: Long) {
override def toString = "|%s| |%s|, |%s|, |%s|".format(id.toString,
source, target, content)
lazy val formattedDate = new SimpleDateFormat("dd.MM.yyyy HH:mm")
format date
}
object comments extends Magic[comments]
And the piece of code:
def loadComments(username: String) = SQL("""select c.*, u.* from
comments c, usr u where c.source = u.ccall and c.target = {ccall}
order by c.date desc""").on("ccall" -> username).as(comments ~< usr *)
Can anyone give me some pointers? I'm really stuck on this.. Here is the stacktrace:
play.exceptions.JavaExecutionException: ColumnNotFound(comments.id)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:228)
at Invocation.HTTP Request(Play!)
Caused by: java.lang.RuntimeException: ColumnNotFound(comments.id)
at scala.Predef$.error(Predef.scala:58)
at play.db.anorm.Sql$.as(Anorm.scala:984)
at play.db.anorm.Sql$class.as(Anorm.scala:919)
at play.db.anorm.SimpleSql.as(Anorm.scala:829)
at controllers.Profile$.loadacomments(Profile.scala:21)
at controllers.Profile$.loadacommentsWithLikes(Profile.scala:46)
at controllers.Profile$.comment(Profile.scala:91)
at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:543)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:499)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:493)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:470)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:158)
Thank you!

On this specific case, the mysql driver was an old one that made the names look really strange. I just updated the driver and everything came back to place.
You can check the thread in google groups here: http://groups.google.com/group/play-framework/browse_thread/thread/3bd8d3ccb5a51d10/e7074ad34ac637da?lnk=gst&q=Jos%C3%A9+Leal#e7074ad34ac637da

I assume that comments magic works for trivial queries? Have you tried not aliasing the table?
If that fails, I have a fairly hackish solution to it. Which is how I'm using Anorm with Postgres. I had to edit the Anorm source code to look for just the <column name> and not <table name>.<column name>. But that brings along a the problem that Anorm can't identify which column is which in a JOIN. So I had to resort to naming all my columns uniquely.
Alternatively, you could try pulling the latest play-scala code from github, but I don't know if there's any significant progress regarding this issue.

Not sure, but I've seen it where when you query multiple tables with Table1., Table2., and they BOTH have a column by the same name... such as "ID", then they get returned as
ID_A, ID_B, etc... then the other columns. So, if your USR table has a column called "ID" also, then this might be what you are running into.
If so, you could either explicitly list all the columns from the USR table and NOT include that table's ID column...
OR
add a column to your query
select C.ID as MyCTableID, C., U. ...
Then, you KNOW you will explicitly have a column called "MyCTableID" to run with.

Related

Cannot apply Flyway migration for a PostgreSQL table

In my Java app, I have the following migration file:
-- code omitted for brevity
create table if not exists demo_table
(
id bigint not null,
"company" varchar(50) not null,
"name" varchar(50) not null
);
create unique index if not exists demo_table_uuid_company_key
on demo_table (uuid, "company");
create index if not exists demo_table_name_company_key
on demo_table ("name", "company");
Although I can run the sql part part part or at a time on PostgreSQL query window, when running my Java app, it throws the following error:
"Unable to create index (name, company) on table demo_table: database column 'name' not found. Make sure that you use the correct column name which depends on the naming strategy in use (it may not be the same as the property name in the entity, especially for relational types)"
I tried many thing e.g. removing the related migration row from flyway_schema_history table, delete indexes on demo_table, etc. But still the same error. If I try to remove double quotes ("") from name, it gives checksum error. So, as the name is reserve word, I use with double quotes. How can I fix it?
On the other hand, I am not sure if I should change these parameters on application.yml:
spring:
flyway:
enabled: true
jpa:
hibernate:
ddl-auto: update
Some minor issues with the script:
Missing comma on first column of create.
This column is also called id but the index references uuid.
Resolving this allowed the script to work perfectly for me (with the quotes as you have them)
If you make these changes and get a checksum error, please run flyway repair

Insert Returning Query For MySQL in JOOQ

am trying to use the following code to get the auto generated id . My back end is MySQL. Code looks like this
Record record = create.insertInto(CANDIDATE, CANDIDATE.FIRST_NAME,
CANDIDATE.LAST_NAME,CANDIDATE.EXTRACTED_NAME)
.values("Charlotte", "Roche","Charlotte Roche")
.returning(CANDIDATE.ID)
.fetchOne();
System.out.println(record.getValue(CANDIDATE.ID));
I am getting NullPointerException. I took a look at http://www.jooq.org/javadoc/latest/org/jooq/InsertReturningStep.html .
It says
Derby, H2, Ingres, MySQL, SQL Server only allow for retrieving IDENTITY column values as "generated key". If other fields are requested, a second statement is issued. Client code must assure transactional integrity between the two statements.
As per my understanding in Mysql auto_increment works as IDENTITY. Can anybody please throw some light on how to achieve this for MySQL
I have taken a look at this SO Question on a similar topic and tried following
Result<?> record =
create.insertInto(CANDIDATE, CANDIDATE.FIRST_NAME, CANDIDATE.LAST_NAME,CANDIDATE.EXTRACTED_NAME)
.values("Charlotte", "Roche","Charlotte Roche")
.returning(CANDIDATE.ID)
.fetch();
System.out.println(record.size());
Though it inserts record in the backend but it prints the record.size() as zero
I'm know that I'm late for the party.
But I hope I can help someone with similar problem,
Derby, H2, Ingres, MySQL, SQL Server only allow for retrieving IDENTITY column values as "generated key". If other fields are requested, a second statement is issued. Client code must assure transactional integrity between the two statements.
The words "generated key" is the problem.
You can check if your table id is AUTO_INCREMENT or not by using SHOW CREATE TABLE $table_name. I think it is not.
P/s: I'm using MySQL
Just did a test inserting a record and retrieving the generated id from within a Spring service without any problem.
So yes, auto_increment in MySQL works as IDENTITY with jOOQ.
The MySQL table looks like this:
CREATE TABLE persons (
`id` mediumint(9) NOT NULL AUTO_INCREMENT,
`first_name` varchar(64) NOT NULL,
`last_name` varchar(64) NOT NULL,
primary key(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
and the service like this:
public Result<PersonsRecord> insertPerson(String firstName, String lastName) {
Result<PersonsRecord> result =
dsl
.insertInto(
PERSONS,
PERSONS.FIRST_NAME,
PERSONS.LAST_NAME)
.values(
firstName,
lastName)
.returning(PERSONS.ID)
.fetch();
logger.debug("Person ID: " + result.getValue(0, PERSONS.ID));
return result;
}
The generated id is available straight away after executing the insert:
Person ID: 4
Maybe there is a problem with transaction.
Insert might not yet persisted those values in database, so nothing is fetched.
Also I think that IDENTITY in case of MySQL is not made by AUTO_INCREMENT but PRIMARY KEY (...)
https://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html

How to use Collate in Hibernate for french char set

Hi I'm trying to use collate on a view which has column name per_va_first_name when I use the following query :
SELECT *
FROM person_view
WHERE NLSSORT(per_va_first_name, 'NLS_SORT = FRENCH_AI') = NLSSORT('mickaël', 'NLS_SORT =FRENCH_AI')
I get the error
ORA-12702: invalid NLS parameter string used in SQL function
I'm new to oracle and this nlssort. Can anyone help me in pointing out what's my mistake?
And at the same time I want to use collate in Hibernate for Java. Same french char set.
Edit:
When I use these commands in sql
alter session set nls_sort=French_AI;
alter session set nls_comp=linguistic;
I get the desired output when this query is executed
SELECT * FROM v_myuser_search_test_ea4 where per_va_first_name like 'Mickaël%'
How to do this in Hibernate? Is there a way I can append 'CI' to French_AI to make it 'French_AI_CI'
According to Oracle documentation found on http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions113.htm#SQLRF51562
you might change your query to
SELECT *
FROM person_view
ORDER BY NLSORT(per_va_first_name, 'NLS_SORT = FRENCH_AI_CI')
Hibernate should understand it, however you are already losing database portability as this is Oracle-specific function.

Updating a SQL table

I am doing a Java program in which I am reading input from some files and if it contains any string that I have in my list I have to update the table with name and its count.
First i created a table as follows
create table mobile(name varchar2(20),count int,primary key(name));
for instance,if I read string like "Sony unviels its new phone", table must be updated with name as sony count as 1.
what my doubt is initially it is an empty table. Can we update it as I said.
Thanks in advance....
First table creation
CREATE TABLE mobile
(
t_name VARCHAR (20),
t_count NUMBER,
PRIMARY KEY (t_name)
);
And insert statement
INSERT INTO mobile
VALUES ('Sony', 1);
Single statement for insert and update
MERGE INTO mobile t
USING (SELECT *
FROM mobile
WHERE LOWER (t_name) = 'sony') s
ON (t.t_name = s.t_name)
WHEN MATCHED
THEN
UPDATE SET t.t_count = t_count+1
WHEN NOT MATCHED
THEN
INSERT (t_name, t_count)
VALUES ('sony', 1);
Either you prepopulate you table with your given word list so something like
CREATE TABLE mobile(
name varchar2(20),
count_column int,
primary key(name)
);
INSERT INTO mobile (name, count_column) VALUES
('Sony', 0);
or you are adding some magic to your Java code which is deciding whether to do an UPDATE or an INSERT.
As an simple would look like theoretical
UPDATE mobile SET count_column to count_column+1 where name = 'Sony';
this will fail if there is none entry given.
You will have to execute an UPSERT like query , since oracle doesn't have it, you have to do a workaround to resolve this. please check this .

java web service working with PostgreSQL database

my code is written in java, and I am really new to java, so i hope my explanations are correct:
i have a java written web service that works with a data base.
the data base types can be PostgreSQL and mysql.
so my webservice works with the JDBC connection for both data bases.
one of my data base tables is table urls,
for postgressql it is created like this:
CREATE TABLE urls (
id serial NOT NULL primary key,
url text not null,
type integer not null);
for mysql it is creates like this:
CREATE TABLE IF NOT EXISTS URLS (
id INTEGER primary key NOT NULL AUTO_INCREMENT,
url varchar (1600) NOT NULL,
type INTEGER NOT NULL );
when I try inserting data to this table I use an entity called urls:
this entity has:
private BigDecimal id;
private String url;
private BigInteger type;
when I try to insert values to the urls table I assign values to the urls entity, while leaving the id as NULL since it is AUTO_INCREMENT for mysql and serial for postgres.
the query works for my sql, but fails for postgress.
in the postgres server log I can see the following error:
null value in column "id" violates not-null constraint
cause I sends NULL as the id value.
I found out that in order for the query to work I should use this query:
INSERT INTO URLS(ID, TYPE, URL) VALUES(DEFAULT, 1, 'DED'); or this one:
INSERT INTO URLS(TYPE, URL) VALUES(1, 'DED'); or this one:
instead of this one, that I use:
INSERT INTO URLS(ID, TYPE, URL) VALUES(NULL, 1, 'DED');
so my question is,
how do I assign the DEFAULT value to a BigDecimal value in java ?
is removing the id from my entity is the right way to go ?
how can I make sure that any changes I do to my code wont harm the mysql or any other data base that I will use ?
If you specify the column name in the insert query then postgres does not take the default value. So you should use your second insert query.
INSERT INTO URLS(TYPE, URL) VALUES(1, 'DED');
This syntax is correct for both postgres and MySQL.
This should resolve your question (1) and (3). For (2) DO NOT delete the id field from your entity. This id is going to be your link to the database row for a specific object of the entity.
1 - I think it is proper to use Long or long types instead of BigDecimal for id fields.
2 - Yes it generally helps, but it lowers portability. BTW, using an ORM framework like Hibernate may be a good choice.
3 - Integration testing usually helps and you may want to adopt TDD style development.
When using this statement:
INSERT INTO URLS(ID, TYPE, URL) VALUES(NULL, 1, 'DED');
you are telling the database that you want to insert a NULL value into the column ID and Postgres will do just that. Unlike MySQL, PostgreSQL will never implicitely replace a value that you supply with something totally different (actually all DBMS except MySQL work that way - unless there is some trigger involved of course).
So the only solution to is to actually use an INSERT that does not supply a value for the ID column. That should work on MySQL as well.

Categories