Is there a way to use SQL Server table-valued parameters in Entity Framework in a way that doesn't require you to use a stored procedure or string-based queries like context.Database.ExecuteSqlCommandAsync("") ?
Something similar to Dapper where I can pass a DataTable and specify the user-defined type name to use. Probably must be some sort of overload of IEnumerable<>.Contains() or .Join() so that I can build a join in a generated query.
The goal is to stay with expression trees and don't mess with strings.
Related
I'm using the #sap/hana-client npm module in a NodeJS project to connect to a HANA database and run queries.
I have a list of IDs that I want to include in a WHERE ID IN(...) SQL clause via parameterized queries, but cannot seem to figure out the syntax to do it.
Here's what I imagine it would look like (but this does not work, fails at the parameter binding stage)
const ids = [1,2,3,4];
const params = [ids];
const sql = "SELECT * FROM T WHERE ID IN (?)";
// this fails with => code: -20007, message: 'Can not bind parameter(0).', sqlState: 'HY000'
conn.query(sql, params, (err, result) => {
// process query results or errors
});
I know that in Postgres I can do this by using the UNNEST(...) 1 array function, but the same does not seem to work in HANA
That's a well-known difficulty with HANA.
ARRAY-like types are not natively supported in the client software.
Your (special) case of this, namely turning an array into a list of parameters for an IN clause requires some additional efforts.
See e.g. Errors with declared array/table variable values in SAP HanaDB SQL
The bottom line is that Postgres handles this special case specifically by replacing the single IN-clause parameter ? with a whole list of delimited values.
HANA does (sadly) not do something like that.
Instead, if you have to know in advance how many elements (at max) the IN-list will have so that you can prepare a statement with a parameter ? for each of those elements.
Alternatively, you can use SQLScript and the UNNEST construct that I've shown in the linked question, or you can create a temporary table, fill it with the IN-list elements and use it in the IN-clause (or join it).
Either way, it's rather cumbersome to manually do this, and I'd probably look for a framework that does that sort of stuff.
From a great reply:
in PostgreSQL, CREATE FUNCTION is indeed a "SQL statement" but is is merely a
"wrapper" to specify a block of code that is executed by something
different than the SQL query "engine". Postgres (unlike other DBMS)
supports multiple "runtime engines" that can execute the block of code
that was passed to the "CREATE FUNCTION" statement - one artifact of
that is that the code is actually a string so CREATE FUNCTION only
sees a string, nothing else.
What are the consequences of "the code is actually a string so CREATE FUNCTION only sees a string, nothing else"?
Is that considered as dynamic SQL? Does it prevent or introduce SQL injection risk, compared to dynamic SQL?
How is that different from other RDBMS (if any?) where "the code is not a string"?
Thanks.
PostgreSQL is highly extensible, and you can for example define your own procedural language to write functions in.
PostgreSQL knows nothing about the language except that it has to call a certain language handler to execute the function.
The way that was chosen to implement this is to simplify pass the code as a string.
This is just an implementation detail and does not make PostgreSQL functions any more or less vulnerable to SQL injection than other RDBMS.
There are several levels on which you have to defend yourself against injection:
The function arguments: Here you should choose non-string data types whenever possible.
The SQL statements within the function: Here you should avoid dynamic SQL whenever possible, and if you have to use dynamic SQL, you should insert variables using the %L pattern of the format function.
Again, this is the same if function bodies are specified as strings or not.
All 3GL+ code is basically a string. The "parameter" passed to CREATE FUNCTION is code (to be executed outide the core SQL engine), which is a string (that's not SQL).
Other RDMS's only support SQL as the function/procedure body.
I have an Oracle function that returns a nested table of an Oracle user defined type.
If I call the function from TOAD or SQL developer with a syntax like this:
SELECT * FROM TABLE(MYFUNCTION('SOME_STRING_PARAM'))
I get the expected result.
I am even able to create .NET classes from Visual Studio Server Explorer wizard for the user defined types.
However when I try to create import function from the Entity Framework model wizard I don't get a proper option to define the returned type.
Am I trying to do something not supported?
Import function doesn't behave the way you might expect with ODP.NET. It assumes that the first SYS_REFCURSOR it finds as an OUT parameter is the "return value" of the Entity Function.
Therefore, you will need to wrap your function with a stored procedure that places the nested table data in a REF CURSOR.
Then you need to learn about the required metadata in the config file for this REF CURSOR. In the online help for Oracle Developer Tools for Visual Studio, read the Entity Framework section for more information.
Here is a walkthrough that shows how to set up an Import Function:
https://apex.oracle.com/pls/apex/f?p=44785:24:106387346683725:::24:P24_CONTENT_ID,P24_PROD_SECTION_GRP_ID,P24_PREV_PAGE:10068,,24
Due to the complexity of all this, I don't advise using Imported Functions with non scalar Oracle Stored Functions or Procedures return values unless you absolutely have to.
I tried to call linq query from sliverlight application to web service which is 'ADD.NET Entity Data Model' with 'WCF Data Service'. The linq below is working (e.g.using pre-defined table & field names):
var query = from o in context.ORDER
where o.NUMBER == 1
select o;
((DataServiceQuery<ORDER>)query).BeginExecute(OnQueryComplete, query);
But I need dynamically assign different table and fields names to the linq query. Is there any way? Do I need to write a method in WCF to execute any sql command?
Thanks for any help.
You can use the Dynamic Linq samples to provide dynamic field names in where clauses - see: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Further, you can do this in a type-safe way using PredicateBuilder - http://www.albahari.com/nutshell/predicatebuilder.aspx
For more dynamic behavior - including dynamic table names - the only Linq option I can think of is to compile some code at runtime within your app using the CSharpCodeProvider (http://support.microsoft.com/kb/304655). However, obviously you need to be careful with security when offering this from a web service.
I am working in a previously existing grails project that has some search functionality built into it. It has created a new Sql object using my SQL Server datasource, and it seems like it is attempting to call a stored procedure like so:
def qResults = sql.rows(spCall)
where spCall is a String and looks like this:
EmployeeQueryClient 'SomeClient', 1,1,0
Where "EmployeeQueryClient is the name of the stored procedure, and the other things are the parameters.
I can't find any documentation supporting this kind of call - is this correct? How would I really do this if it is not?
In the code shown above sql is an instance of groovy.sql.Sql. This provides a rows(String sql) method that can be used to execute SQL and returns the result.
Generally speaking, I think this rows method is a bad choice if you want to call a stored proc, because you have to concatenate the name of the proc and all the args into a single string, which is a bad idea from the point of view of both type safety and readability.
Instead use one of the overload call methods provided by the same class, which are specifically intended for invoking stored procedures. For example, if you just want to invoke the procedure (ignoring any results it returns) use:
sql.call("{call EmployeeQueryClient(?, ?, ?, ?)}", ['SomeClient', 1, 1, 0])
The syntax used here for calling a stored proc,
{call PROC_NAME(PROC_ARGS)}
will work for MySql. If you're not using MySql you'll need to replace this with whatever is used by your RDBMS to invoke a stored proc.
Overloaded versions of the call method enable you to handle any results returned and/or ouput parameters of the stored proc.