How to use Dapper LINQ with TableDirect (without embedded SQL) with ORACLE? - linq

I tried DapperExtensions, Dapper.Extensions.Linq and linq2dapper to no avail. I will try Dapper.SimpleCRUD-with-Oracle. I will probably settle with a Stored Procedure instead. I want to use TableDirect with no embedded SQL statement. How can I use Dapper and Linq with a TableDirect? Or, how can I use TableDirect without embedded SQL, and filter a table?
Following are my problems:
I could not create Predicate without run time error.
I need missing configuration
I got ORA error about table saying "column not correct, runtime error".
How to use Dapper LINQ with TableDirect (without embedded SQL) with ORACLE?

You can achieve this with simple Dapper. For example, look at the following code from Dapper:
public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = default(int?), CommandType? commandType = default(CommandType?));
Look at the last commandType parameter. It supports the TableDirect value that you are looking for.
As far as other extensions of Dapper you mentioned in question, I do not think they will support it. I know for sure Dapper Extensions do not support it; not sure about others.
This is because, those extensions are basic query generators written over Dapper. So, you are using them for generating the query and in that case, that parameter value will/should be Text. If you want to use other values, bypass the extension and use simple Dapper.
If you want to simply provide a table name or stored procedure name, why use query generator? Just use Dapper.

I used //https://github.com/jmo21/Dapper.SimpleCRUD-with-Oracle-/blob/master/Dapper.SimpleCRUD/SimpleCRUD.cs . No nuget package for this ORACLE dialect. It just obfuscates the WHERE clause, and it is an answer, when I the organization probably will not like SELECT.. FROM ... WHERE...
We don't have SQL injection possible in any case.

Related

Migration to SpringBoot 3: trunc a date with oracle driver no longer works (hibernate)

I am currently migrating a SpringBoot 2.7 application to SpringBoot 3. The following query is used within a SpringData repository:
#Query("select b from #{#entityName} b where (trunc(b.date) <= trunc(:date))")
List<T> findByDate(LocalDateTime date);
While this works great in SpringBoot 2.7, with SpringBoot 3 the following message is thrown:
org.hibernate.QueryException: Parameter 1 of function trunc() has type NUMERIC, but argument is of type java.time.LocalDateTime
Unfortunately, a simple migration to datetrunc was unsuccessful:
Error Msg = ORA-00904: "DATETRUNC": ungültige ID
Does anyone have a solution for this?
Best regards
So, as I noted in my previous answer, there's no standard HQL function for date truncation. That's because it would be quite difficult to implement in most SQL dialects (I have not really investigated to see quite how difficult, but it's at least nontrivial.)
However, just especially for you, in Hibernate 6.2, which should go into CR today, what I have done is added undocumented (but tested) support for the date_trunc() function under Postgres, DB2, Oracle, and H2. On Oracle, this translates to trunc(), of course.
For example, you could write:
date_trunc(year,current_timestamp)
When I say it's "undocumented" I mean you use it at your own risk. (The documented way to do this remains to use a FunctionContributor.)
I hope that helps.
UPDATE:
Oh and by the way, I just noticed that you're not actually using the full form of the trunc() function in your query. You're actually just stripping off the time part of a timestamp.
There's actually multiple ways to do that in HQL without needing to use the Oracle-specific trunc() function. (But of course trunc()/date_trunc() can do more things that you're not using here.)
JPA-standard way
One of the improvements I added to the new JPA 3.1 specification was to let you write:
extract(date from current_timestamp)
To strip off the time part of the timestamp.
HQL alternative
But you can also do it using the HQL cast() function if you prefer:
cast(current_timestamp as Date)
These two options translate to the same SQL on Oracle.
In Hibernate 6 we started checking the argument types of HQL functions.
Since trunc(numeric,places) is a very common function across many dialects of SQL, we register it as one of the known functions, though we have not yet promoted it to a “standard” HQL function (perhaps we should).
On the other hand, Oracle’s trunc(date) is extremely specific to Oracle and is more like the date_trunc() function on DB2 and Postgres. We have not (so far) attempted to standardize on any sort of function for timestamp truncation, and I don’t consider it a high priority. This function is not registered by OracleDialect.
So, therefore, if you try to call trunc() on a Date, you will get a typing error.
Now, in general, in Hibernate 6.x:
We do not guarantee that Hibernate Dialects know about every single SQL function in your database, and you can't depend on that.
Instead we have a rather long list of documented HQL functions that we promise work portably across every database we support. (Right now trunc() is not on that list, but it almost made it onto the list.)
And that's perfectly fine, because we also provide APIs that make it very easy to register new SQL functions, either platform-specific functions like this one, or functions you've written yourself, either by:
writing a custom Dialect, or
providing a FunctionContributor.
https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-user-defined-functions
Alternatively, if that's too much work, you can just use the JPA-standard syntax for calling native SQL functions, which is function('trunc', date, 'YEAR'), but I consider this a bit unlovely.
I'm using Oracle database and after migration to new hibernate I had the same issue.
I solved it by overriding org.hibernate.dialect.OracleDialect and adding ORACLE_TRUNC function to a functionRegistry. I've used the same definition trunc function definition as in Hibernate < 6 Oracle8iDialect.
public class CustomOracleDialect extends OracleDialect {
public CustomOracleDialect() {
super();
}
#Override
public void initializeFunctionRegistry(FunctionContributions functionContributions) {
super.initializeFunctionRegistry(functionContributions);
functionContributions.getFunctionRegistry().register("ORACLE_TRUNC", new StandardSQLFunction("trunc"));
}
}
Configure hibernate to use this dialect inapplication.properties / application.yml file:
spring:
jpa:
database-platform: com.example.CustomOracleDialect
In your queries use ORACLE_TRUNC() instead of TRUNC().
I tried using DATE_TRUNC(date, my_date) function from hibernate 6.2 RC2 as Gavin King said - but it transformed my query to CAST(my_date AS DATE) instead of TRUNC(my_date) causing date comparison issues.

Filtering query with R2DBC

I need do a filtering query with some query parameter. I need that if the query parameter is null, the condition of the query (= or LIKE, for example) is not evaluated and return me everything. I'm using R2DBC and I don't find a way to solve it.
If you are using Spring Data R2dbc, besides the above raw SQL query, you can use R2dbcOperations to compose Criteria by condition freely.
The following is an example.
template
.select(Post.class)
.matching(
Query
.query(where("title").like("%" + name + "%"))// extract where here you can assemble the query condition freely.
.limit(10)
.offset(0)
)
.all();
Additionally using R2dbcRepository and convention-based method, try to use a default value in the like(eg. set the null to empty string "" in like) to save work to determine if it is a null value in sql.
A general prepared statement which would work might be:
SELECT *
FROM yourTable
WHERE col = ? or ? IS NULL;
In the event that you bind a NULL value to the ? from your obfuscation layer, the WHERE clause would always be true, returning all records in the table.
If you prefer doing this with a "static SQL statement" (meaning you use a single SQL string for all possible bind values), then, in Oracle, it's probably optimal to use NVL() to profit from an Oracle optimiser feature, as explained in this article, irrespective of whether you're using R2DBC:
SELECT *
FROM t
WHERE col = nvl(:bind, col)
However, a query like yours is often best implemented using dynamic SQL, such as supported by a third party library like jOOQ:
Flux<TRecord> result =
Flux.from(ctx
.selectFrom(T)
.where(bind == null ? noCondition() : T.COL.eq(bind))
);
You can obviously also do this yourself, directly with R2DBC and your own dynamic SQL library, or any other such library.
Disclaimer: I work for the company behind jOOQ.

User-Defined Function Nested in Macro - Framework Manager

We are trying to create a dynamic query subject filter. To do this, we are trying to nest an Oracle user-defined function inside of a macro.
Example query subject filter:
#strip(ORACLE_USER_DEFINED_FUNCTION())#
We have imported the oracle function ORACLE_USER_DEFINED_FUNCTION into Framework Manager. The function returns a VARCHAR2 of the desired expression. For testing purposes, this function is simply returning VARCHAR2 value of '1=1' (the single quotes are not part of the VARCHAR2 return value).
The idea being that we want the query subject filter expression to be dynamically generated at run-time so the resulting query contains '...WHERE 1=1'. The strip macro is the mechanism to pre-process and invoke the user-defined function before the query is sent to the database.
However, when attempting to verify/check the query subject filter we receive the following error.
XQE-GEN-0018 Query Service internal error has occurred, please see the log for details.
I'm trying to get a hold of the query service log, but don't yet have it.
Perhaps there is some casting needed to convert the oracle VARCHAR2 output from the function to an IBM/Cognos string that is acceptable input for the IBM/Cognos macro.
Your assistance is appreciated. Thanks in advance.
Using Oracle 12c and Cognos 11.1.
With the exception of the queryValue macro function, macros are evaluated prior to accessing the database. This means the macro does not know what the Oracle UDF is or what its supposed to do. If you are able to call the UDF via a FM query subject you maybe able to get away with something similar to the queryValue answer found here:
Cognos 11.1.7 Framework manager change the table for the query subject, type data

Nhibernate Update timestamp

Is there a way to do
"UPDATE Item SET start_date = CURRENT_TIMESTAMP" ?
in Nhibernate without using hql/sql.
I am trying to avoid hql/sql because the rest of my code is in criteria. I want to do something like :
var item = session.get<Item>(id)
item.start_date = current_timestamp
There are two ways and sql is correct one.
Either you will
load all entities, change, update and commit, or
write sql query and let dbms handle most of the work
I am trying to avoid hql/sql because the rest of my code is in criteria
That is not a valid argument. Criteria is an API intended for relational search, and it does not support mass updates.
Different tasks, different APIs.
In this case, you can use either HQL or SQL, as the syntax is the same. I recommend the former, because you'll be using your entity/property names instead of table/column ones.

When using Linq, is DbNull equivalent to Null?

This is not about DBNull vs Null. I understand the difference.
What I would like to know is if I am using Linq, say to access a User.EmailAddress, then checking User.EmailAddress == null is the same as User.EmailAddress == DBNull correct?
My reasoning is that the absence of data in the database results into Linq not generating an object reference, which then means that null is in fact equivalent to DBNull when used with Linq.
Is my reasoning correct or not?
You shouldn't use DBNull with LinqToSql. The point is Language Integration, and so one concept or name for null will suffice.
Here's the select statement that works in LINQ to SQL for Visual Basic. I assume it will be the same in C#.
User.EmailAdress.Equals(Nothing)
For example:
Dim EmptyEmailAddressEntries = From User in DC.Users _
Where User.EmailAddress.Equals(Nothing) select User
Will give you all the Users that have nothing in the email address. To check for entries with space " " characters only add
Or
User.EmailAddress = ""
In LINQ to SQL, you should be using null rather than DBNull. LINQ to SQL is an OR mapper, so it works with objects in a native way. The whole goal with L2S is to allow you to work with objects in a standard .NET way, and let L2S handle all the mapping between native and DB specific for you. You should avoid using DBNull in any L2S statements...in fact, I'm not even sure that is even a valid check (it'll probably cause some odd behavior if it works at all.)

Resources