Hibernate native sql query - sql

Perfectly fine ms-sql statement
SELECT distinct ProductLineCode ,
(SELECT CAST(ItemName + ', ' AS VARCHAR(MAX)) FROM Product spt
where spt.ProductLineCode = pt.ProductLineCode FOR XML PATH (''))
as ItemNames FROM Product pt where ProductLineCode is not null
cause error when executed as native query in hibernate.
org.hibernate.MappingException: No Dialect mapping for JDBC type: -16
I guess that JDBC type: -16 is boolean but that says me nothing. Product table has xml mapping and works well for months.
Could you please guide me what to try next?

You might as advised in comments be able to get something similar to work by changing the types in the sql.
But if that doesn't bring success, you might also be able to tell hibernate how to deal with this type by changing the Dialect class used by your application, possibly even extending the one currently used and adding a registration for the missing type.
It appears that your missing type mapping is for the type java.sql.Types.LONGNVARCHAR (by code grep, the value is -16), so a Dialect extension with a call something like
registerColumnType( Types.LONGNVARCHAR, "text" );
in the constructor may convince hibernate to treat this field as text.
If you do this you'll have to change the configuration to use your dialect by modifying the line
<property name="dialect">org.hibernate.dialect.SQLServer2012Dialect</property>
to use your own dialect class. (Note: the class in there is just a guess at what you might have there now.)
It's also possible that you just have hibernate using the wrong dialect for your DB, in which case just changing the configuration to the appropriate one would be better.
It's rarely necessary to use a custom Dialect, but this may be one of those times.

Related

SQL data types for AnyLogic

I am saving the output of my AnyLogic model into an SQL server database. For non-AnyLogic aficionados, AnyLogic is based on Java. However, I am not sure what data types I need to specify for my columns in the database.
So far I am using these:
double in AnyLogic : float in SQL
string in AnyLogic : varchar in SQL
int in AnyLogic : int in SQL
I also have parameters that are of type Option list, which is, if I understand correctly, a form of Java enum. I tried to save those parameters as varchar, but this (obviously) does not work. In addition, my model contains various boolean parameters. For my boolean parameters, I add columns of type bit in SQL by running:
ALTER TABLE myTable
ADD my_bool BIT NOT NULL DEFAULT 0;
However, running the model returns this error
SQLServerException: Invalid column name 'false'. Caused by: Invalid column name 'false'
So concretely, how can I export parameters of type Option list and boolean?
This addresses the original question which was tagged MySQL.
I don't know all the issues around "option list". Seems like a string (with a length such as varchar(255)) would work. You can also look into the built-in enum type, although I would not normally recommend using enums.
I would recommend using boolean instead of bit as the equivalent for boolean. Seems more mnemonic.
That said, MySQL understands false as a constant. You can check this by running:
select false
This also works:
select "false"
However, this returns the error that you specify:
select `false`
I suspect that the code being generated is using this construct. You will need to look at the code -- and you might need to figure out some other way of handling this. In MySQL you can use 0 for false and that might fix your problem.
The AnyLogic database is a standard HSQLDB database (not something proprietary) but they've added AnyLogic client functionality to define 'column types' as though they are Java types (with special types for option lists and compiled-on-the-fly-and-run Java code).
If you look at the db.script file (HSQLDB just stores the persistent DB data as an SQL script which creates the tables and INSERTs the values) you can see the underlying HSQLDB types which map closely to SQL Server types.
boolean --> BOOLEAN
double --> DOUBLE
int --> INT
String --> VARCHAR(16777216)
Date --> TIMESTAMP
Code --> VARCHAR(16777216)
Option List --> VARCHAR(255)
NB: The 'Java column types' are supposed to make it easier for a non-technical user to understand what they will get from a Java perspective when querying that column but, for example, they are confusing in that queries will return Java nulls for missing values, so a boolean column actually effectively returns a Boolean.
That should help.
I managed to address part of my problem. I am now able to store String variables from Java into my SQL database. The issue was due to incorrect use of quotations.
Java uses double quotations for String variables (e.g.: ""). SQL expects single quotations (e.g.: '') for string-like columns such as varchar() and char()
I had to amend my SQL query to this:
String insertTableSQL = "INSERT INTO test (my_string) VALUES(" +" '"+my_variable_string+"' )";
Note that my_variable_string is a derivative of a Java enum, which I obtained by executing String my_variable_string= my_enum.name();

How to change the database name dynamically in MyBatis XML file?

I am using Spring Boot with MyBatis. I have the following query in one mapper XML file.
<select id="someFunction" resultMap="someResultMap">
SELECT *
FROM p LEFT JOIN anotherDatabase.table AS q ON p.id = q.id
</select>
Actually "anotherDatabase" is hard-coded in my query because I do NOT want to add another data source for only this query. But how can I make this "anotherDatabase" name dynamically (maybe configure it in some properties file) as it may change in different environment deployed?
Though ugly solution, you can use a parameter: not a traditional JDBC/SQL parameter #{schema} but a direct parameter ${schema}. See the dollar sign ($) there?
When using a direct parameter ${param} you can insert whatever you want into the SQL. Even a entire whole SQL statement if you wish. Use it with care and only as a last resort.
Please carefully consider this insertion of direct parameters into the SQL is susceptible of SQL injection. You need to carefully control the value of the schema property/parameter, so it does not come from the user or any external source. If you do it like this, it will be safe to use.
However, a cleaner solution is to use a separate datasource. The only drawback is you may need to enable two-phase commit if you need transactions that emcompass tables from both datasources.

How do I declare a variable for a hard coded database?

I have some hard coded database values in my SQL and I need to convert to variables , I have declared them in places but I need Production2 to be changed to #Source_Database_Name variable below but I dont know how to place it in with the Information Schema just after it without getting a syntax error
IF EXISTS(SELECT * FROM Production2.INFORMATION_SCHEMA.COLUMNS
I guess that the only way you can do this is dynamic sql generation (unfortunately). And there's actually quite a few reasons (from database engine's perspective) for not allowing a user to parametrise queries in a way you want. The one that sits on top of my head is that it will make impossible to validate syntax of your query (no way to know that you're referring to what actually exists).
In case you're talking about "being able to execute the same set of SQL against different database(s)" and you're actually executing this sql from code (.NET / anything), you can achieve the same result by specifying target database in connection string (i.e. by changing the level where you set database -- not in the [sql] script, but rather at some external point).

NHibernate mapping: is it possible to insert values into the database via a mapping file without using a property?

I am writing an application which works with a legacy database (brownfield). I have a couple of tables in which I insert data. These tables have some fields which need values of which I do not want the properties in my domain entities. Is there a way to insert the default value into the field without having to create a property for it my mapping file? I cannot alter the database to create a trigger, so it has to be done via the mapping file/.net application.
Hope someone can help. I hoped I could use a formula, but that doesn't work and I couldn't find any other ways to do it either.
you could use a private / protected property.
That would mean introducing these fields into your domain model / mappings, but they would be limited to those, and not exposed to whoever uses your entities.
seems like a reasonable compromise to me.
You could use EventListeners
in the OnPostInsert / OnPostUpdate event you can get the db connection and ad-hoc execute a sql query.
NH makes it rather easy
using xml see here
using FluentNHibernate see here
the basic idea is to use PropertyAccessor on a non existing property which always has the constant value.

Mapping to varchar and nvarchar in hibernate

If there are 2 columns in database, eg.
code varchar(3)
name nvarchar(50)
How to tell hibernate to pass varchar for searching by code?
In the hibernate mappings string is mapped to nvarchar and it produces queries like:
Select code, name From table where code=N'AAA' (instead of code='AAA')
This is very bad as it causes index scan instead of index seek operation (scanning all index nodes instead of directly going to requested one)
As code is used in millions of rows as well as in several indexes and foreign keys, changing it from varchar to nvarchar will cause performance degradation (more IO operations as nvarchar uses twice more space than varchar).
Is there any way to tell hibernate to do mapping according to database type, not to Java type?
Thanks
Probably you already solved this, but I had a similar problem.
I'm using jTDS JDBC driver and I solved the index scan problem by adding:
;sendStringParametersAsUnicode=false;prepareSQL=0
to the end of the jTDS connection string.
Probably it would not had solved your problem because by doing this, jTDS will only use VARCHAR (no NVARCHAR anymore).
Also, I had to disable the prepared SQL, because Hibernate is using 'like' instead of '=' when generating the queries and by using 'like' combined with a variable (SELECT ... WHERE column LIKE #var) causes an index scan (MSSQL 2000).
I'm assuming you're talking about NHibernate rather than Hibernate because the latter does not use nvarchar in its default SqlServer dialect.
The way to solve your problem is to specify column type as "AnsiString" in your mapping:
<property name="Code" type="AnsiString"/>
Take a look at this post for more details.
<type-mapping>
<sql-type jdbc-type="NVARCHAR" hibernate-type="string" />
</type-mapping>
Add the above code in the hibernate reveng file.
In hibernate.properties set the property hibernate.connection.defaultNChar=false.
You can either hide your tables behind views or use nstring type. This type is available in hibernate-core 4.x. In hibernate-core 3.6.10.Final you will need to define the custom type nstring - see the comment in the url:
Getting Hibernate and SQL Server to play nice with VARCHAR and NVARCHAR.