Error using Join on uniqueidentifier - convert uniqueidentifier to numeric - nhibernate

I am using Fluent NHibernate on sqlserverce.
Using NHibernate QueryOver I try to retrieve a row - NHibernate generate automatically a a join query
and I get the following Exception:
[SQL: SELECT tag FROM CheckpointToProtectionGroup cp2pg
JOIN CheckpointStorageObject cp ON cp.id = cp2pg.checkpoint_id
JOIN ProtectionGroupCheckpointStorageObject pg ON pg.id = cp2pg.vpg_id
WHERE cp.CheckpointIdentifierIdentifier = 1111 AND
pg.ProtectionGroupIdentifierGroupGuid =
11111111-1111-1111-1111-111111111111]
---> System.Data.SqlServerCe.SqlCeException:
The conversion is not supported.
[ Type to convert from (if known) = uniqueidentifier,
Type to convert to (if known) = numeric ]
From what I see, it seems that it tries to convert the value - 11111111-1111-1111-1111-111111111111 to numeric but this value is a Guid field:
CheckpointToProtectionGroup checkpointToProtectionGroup = Session
.QueryOver<CheckpointToProtectionGroup>()
.JoinQueryOver( row => row.ProtectionGroup)
.Where(row => row.ProtectionGroupIdentifier.GroupGuid ==
protectionGroupIdentifier.GroupGuid)
.SingleOrDefault();
ProtectionGroupIdentifier.GroupGuid is of Guid type

Looks like your GroupGuid value is not correctly converted to SQL. It should have single quotes around the value.
pg.ProtectionGroupIndentifierGroupGuidId = '11111111-1111-1111-1111-111111111111'
SQL Server tried to convert left hand value from uniqueidentifier (Guid) to numeric, since the right hand value is numeric value - numeric subtract operation with few operands.
You have protectionGroupIdentifier.GroupGuid value in Where part of your QueryOver expression. Check if GroupGuid is indeed Guid property. If it's an object property, cast it to Guid.

Related

Cast values in update query

I have this SQL native query which I want to use from Spring JPA repository:
update words
set low_range = :lowRange, high_range = :highRange
where keyword = :keyword
Error:
ERROR: column "low_range" is of type numeric but expression is of type bytea
I use this column definition:
#Column(name = "low_range")
private Float lowRange;
How I can convert or cast the value into this update query?

POSTGRES JSON: Updating array value in column

I am using POSTGRES SQL JSON.
In json column the value is stored as array which I want to update using SQL query
{"roles": ["Admin"]}
The output in table column should be
{"roles": ["SYSTEM_ADMINISTRATOR"]}
I tried different queries but it is not working.
UPDATE public.bo_user
SET json = jsonb_set(json, '{roles}', to_jsonb('SYSTEM_ADMINISTRATOR')::jsonb, true);
UPDATE public.bo_user
SET json = jsonb_set(json, '{roles}', to_jsonb('["SYSTEM_ADMINISTRATOR"]')::jsonb, true);
ERROR: could not determine polymorphic type because input has type unknown
SQL state: 42804
Kindly help me with the query
but at the moment it is to update the value at 0 index
That can be done using an index based "path" for jsonb_set()
update bo_user
set "json" = jsonb_set("json", '{roles,0}'::text[], '"SYSTEM_ADMINISTRATOR"')
where "json" #>> '{roles,0}' = 'Admin'
The "path" '{roles,0}' references the first element in the array and that is replaced with the constant "SYSTEM_ADMINISTRATOR"' Note the double quotes inside the SQL string literal which are required for a valid JSON string
The WHERE clause ensures that you don't accidentally change the wrong value.
So this worked.
UPDATE public.bo_user
SET json = jsonb_set(json, '{roles}', ('["SYSTEM_ADMINISTRATOR"]')::jsonb, true)
where id = '??';

Setting a Clob value in a native query

Oracle DB.
Spring JPA using Hibernate.
I am having difficulty inserting a Clob value into a native sql query.
The code calling the query is as follows:
#SuppressWarnings("unchecked")
public List<Object[]> findQueryColumnsByNativeQuery(String queryString, Map<String, Object> namedParameters)
{
List<Object[]> result = null;
final Query query = em.createNativeQuery(queryString);
if (namedParameters != null)
{
Set<String> keys = namedParameters.keySet();
for (String key : keys)
{
final Object value = namedParameters.get(key);
query.setParameter(key, value);
}
}
query.setHint(QueryHints.HINT_READONLY, Boolean.TRUE);
result = query.getResultList();
return result;
}
The query string is of the format
SELECT COUNT ( DISTINCT ( <column> ) ) FROM <Table> c where (exact ( <column> , (:clobValue), null ) = 1 )
where "(exact ( , (:clobValue), null ) = 1 )" is a function and "clobValue" is a Clob.
I can adjust the query to work as follows:
SELECT COUNT ( DISTINCT ( <column> ) ) FROM <Table> c where (exact ( <column> , to_clob((:stringValue)), null ) = 1 )
where "stringValue" is a String but obviously this only works up to the max sql string size (4000) and I need to pass in much more than that.
I have tried to pass the Clob value as a java.sql.Clob using the method
final Clob clobValue = org.hibernate.engine.jdbc.ClobProxy.generateProxy(stringValue);
This results in a java.io.NotSerializableException: org.hibernate.engine.jdbc.ClobProxy
I have tried to Serialize the Clob using
final Clob clob = org.hibernate.engine.jdbc.ClobProxy.generateProxy(stringValue);
final Clob clobValue = SerializableClobProxy.generateProxy(clob);
But this appears to provide the wrong type of argument to the "exact" function resulting in (org.hibernate.engine.jdbc.spi.SqlExceptionHelper:144) - SQL Error: 29900, SQLState: 99999
(org.hibernate.engine.jdbc.spi.SqlExceptionHelper:146) - ORA-29900: operator binding does not exist
ORA-06553: PLS-306: wrong number or types of arguments in call to 'EXACT'
After reading some post about using Clobs with entities I have tried passing in a byte[] but this also provides the wrong argument type (org.hibernate.engine.jdbc.spi.SqlExceptionHelper:144) - SQL Error: 29900, SQLState: 99999
(org.hibernate.engine.jdbc.spi.SqlExceptionHelper:146) - ORA-29900: operator binding does not exist
ORA-06553: PLS-306: wrong number or types of arguments in call to 'EXACT'
I can also just pass in the value as a String as long as it doesn't break the max string value
I have seen a post (Using function in where clause with clob parameter) which seems to suggest that the only way is to use "plain old JDBC". This is not an option.
I am up against a hard deadline so any help is very welcome.
I'm afraid your assumptions about CLOBs in Oracle are wrong. In Oracle CLOB locator is something like a file handle. And such handle can be created by the database only. So you can not simply pass CLOB as bind variable. CLOB must be somehow related to database storage, because this it can occupy up to 176TB and something like that can not be held in Java Heap.
So the usual approach is to call either DB functions empty_clob() or dbms_lob.create_temporary (in some form). Then you get a clob from database even if you think it is "IN" parameter. Then you can write as many data as you want into that locator (handle, CLOB) and then you can use this CLOB as a parameter for a query.
If you do not follow this pattern, your code will not work. It does not matter whether you use JPA, SpringBatch or plan JDBC. This constrain is given by the database.
It seems that it's required to set type of parameter explicitly for Hibernate in such cases. The following code worked for me:
Clob clob = entityManager
.unwrap(Session.class)
.getLobHelper()
.createClob(reader, length);
int inserted = entityManager
.unwrap(org.hibernate.Session.class)
.createSQLQuery("INSERT INTO EXAMPLE ( UUID, TYPE, DATA) VALUES (:uuid, :type, :data)")
.setParameter("uuid", java.util.Uuid.randomUUID(), org.hibernate.type.UUIDBinaryType.INSTANCE)
.setParameter("type", java.util.Uuid.randomUUID(), org.hibernate.type.StringType.INSTANCE)
.setParameter("data", clob, org.hibernate.type.ClobType.INSTANCE)
.executeUpdate();
Similar workaround is available for Blob.
THE ANSWER: Thank you both for your answers. I should have updated this when i solved the issue some time ago. In the end I used JDBC and the problem disappeared in a puff of smoke!

Nhibernate and like statement on XML field

I have a wrapped fluent nhibernate framework that I'm reusing and have no control over the actual mapping.
In my entity object I have a property mapped as string to an XML column in sql.
Hence when I run a query like:
var myResult = (from myTable in DataManager.Session.Query<Table>()
where myTable.thatXmlFieldWhichIsMappedAsString.Contains(AnXmlSnippet))
select myTable).FirstOrDefault();
It is trying to use the LIKE operator in SQL which is invalid on that column type.
How can I get around this without having to select all the rows and converting to List first?
In case, that we do not need .Query() (LINQ), and we can use Criteria query or QueryOver, we can use conversion:
// the projection of the column with xml
// casted to nvarchar
var projection = Projections
.Cast(NHibernateUtil.StringClob
, Projections.Property("thatXmlFieldWhichIsMappedAsString"));
// criteria filtering with LIKE
var criteria = Restrictions.Like(projection, "searched xml");
// query and result
var query = session.QueryOver<MyEntity>()
.Where(criteria)
;
var result = query
.SingleOrDefault<MyEntity>()
;
From my experience this could lead to conversion into small nvarchar(255) - sql server... Then we can do it like this:
var projection = Projections
.SqlProjection("CAST(thatXmlFieldWhichIsMappedAsString as nvarchar(max)) AS str"
, new string[]{}
, new NHibernate.Type.IType[]{}
);

Firebird - How to use "(? is null)" for selecting blank parameters

I am working with an Excel Report linked to a Firebird 2.0 DB and I have various parameters linked to cell references that correspond to drop down lists.
If a parameter is left blank, I want to select all the possible options. I am trying to accomplish this by putting ... WHERE... (? is null), as described in http://www.firebirdsql.org/refdocs/langrefupd25-sqlnull.html , but I get an "Invalid Data Type" error.
I found some Firebird documentation (http://www.firebirdfaq.org/faq92/) where it talks about this error, but it states that "The solution is to cast the value to appropriate datatype, so that all queries return the same datatype for each column." and I'm not quite sure what that means in my situation.
SELECT C.COSTS_ID,
C.AREA_ID,
S.SUB_NUMBER,
S.SUB_NAME,
TP.PHASE_CODE,
TP.PHASE_DESC,
TI.ITEM_NUMBER,
TI.ITEM_DESC,
TI.ORDER_UNIT,
C.UNIT_COST,
TI.TLPE_ITEMS_ID
FROM TLPE_ITEMS TI
INNER JOIN TLPE_PHASES TP ON TI.TLPE_PHASES_ID = TP.TLPE_PHASES_ID
LEFT OUTER JOIN COSTS C ON C.TLPE_ITEMS_ID = TI.TLPE_ITEMS_ID
LEFT OUTER JOIN AREA A ON C.AREA_ID = A.AREA_ID
LEFT OUTER JOIN SUPPLIER S ON C.SUB_NUMBER = S.SUB_NUMBER
WHERE ((C.AREA_ID = 1 OR C.AREA_ID = ?) OR **(? IS NULL))**
AND ((S.SUB_NUMBER = ?) OR **(? IS NULL))**
AND ((TI.ITEM_NUMBER = ?) OR **(? IS NULL))**
AND ((TP.PHASE_CODE STARTING WITH ?) OR **(? IS NULL))**
ORDER BY TP.PHASE_CODE
Any help is greatly appreciated.
If you are not using Firebird 2.5 (but version 2.0 or higher), or if you are using a driver that doesn't support the SQL_NULL datatype introduced in Firebird 2.5, then you need to use an explicit CAST, eg;
SELECT *
FROM TLPE_ITEMS TI
WHERE TI.ITEM_NUMBER = ? OR CAST(? AS INTEGER) IS NULL
This will identify the second parameter as an INTEGER to the driver (and to Firebird), allowing you to set it to NULL.
Now the faq you reference mentions cast the value to appropriate datatype, what they mean is that you should not cast to a data type that might result to conversion errors if it isn't null.
In my example I cast to INTEGER, but if the values are actually strings and you use say "IX0109302" as a value, you will get a conversion error as it isn't an appropriate INTEGER. To prevent that, you would need to cast to a (VAR)CHAR of sufficient length (otherwise you get a truncation error).
If you are using Firebird 1.5 or earlier this trick will not work, see CORE-778, in that case you might get away with something like TI.ITEM_NUMBER = ? OR 'T' = ?, where you set the second parameter to either 'T' (true) or 'F' (false) to signal whether you want everything or not; this means that you need to move the NULL detection to your calling code.