IDbCommand - CommandType.StoredProcedure - c#

I'm just curious if the IDbCommand.CommandType's value makes a difference in terms of performance?
Basically, I could do either set it as CommandType.Text and pass in a SQL query "EXEC sp_my_stored_procedure ..." as the CommandText. Or, I could set it as CommandType.StoredProcedure and pass in a stored procedure name "my_stored_procedure" as the CommandText.
I'm wondering if there is any performance difference here, or is it just a matter of passing in a query calling the SP vs passing in the name of the SP?
A side note, I realize that it could depend on the driver, but am not sure. So, if that's the case, I'd like to know that as well. Thanks!

Using the CommandType.StoredProcedure is more efficient. The impact would be felt dependent on your app's load.
In my opinion it is also cleaner. I would generally use CommandType.Text if there was a need to build the command at runtime (i.e. SELECT id, name FROM Table WHERE.......).
Hope this helps,
Kevin

I reflected into the Informix object: IfxCommand which has an internal property named AdjustedCommandText. It seems that this method formats the string value to send to the driver based upon the CommandType.
What's interesting is that it either returns one thing for TableDirect or another for StoredProcedure. Or, just the stored text. Now, the StoredProcedure one goes deeper. If there are no command paramters it just returns "EXECUTE PROCEDURE ...", but if there are command parameters involved then it builds the string up starting with "{?=CALL ..." or {CALL ...".
So, I can say as far as Informix is concerned there is no difference except for clarity and cleanliness. As far as other database drivers, I don't haven't looked into them yet.

Related

How to pass list of guid as a parameter to a sql command

I need to filter a sql request by passing a list of id to , this is the command:
var command = "select Software.Name as SoftwareName,SoftwareType.Name as SoftwareType from AssetManagement.Asset as Software inner join AssetManagement.AssetType as SoftwareType on (SoftwareType.Id = Software.TypeId) where Software.Id in (#P)";
cmd.Parameters.AddWithValue("#P", authorizedSoftwaresId);
authorizedSoftwaresId is a list of string , containing data like :
"7D23968B-9005-47A9-9C37-0573629EECF9,F1982165-3F6D-4F35-A6AB-05FA116BA279"
with that it returns to me just one row, I tried adding quotes foreach value but i got "converstion from string caractere to uniqueidentifier failed " exception
This is a pretty common problem and the answer might depend on your database engine and whether you're using ADO.Net, Dapper, etc.
I'll give you some hints from my own experience with this problem on both MS Sql Server and PostgreSQL.
A lot of people think AddWithValue is a devil. You might consider Add instead.
The IN (#P) in your SQL statement might be the source of your problem. Try the Any option instead. See Difference between IN and ANY operators in SQL ; I've had success with this change in similar situations.
If all of your inputs are GUIDs, you might consider changing the type to a collection of GUIDs, although I don't think this is the fix, you have to try everything when you're stuck.
If you have to, you can parse the string version of your collection and add the ticks (') around each value. This choice has consequences, like it may prevent you from using a parameter (#P), and instead construct the final SQL statement you desire (i.e., manually construct the entire WHERE clause through string manipulations and lose the parameter.)
Good luck.

how to get exec string for sql management studio from .net code

I am debugging code someone else wrote that calls a lot of stored procedures (sql server 2008 r2) from C# code. The C# code looks like this
SqlCommand sqlCommand = new SqlCommand(strSP, ConnectionOpen());
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.CommandTimeout = intTimeOut;
//System.Data.SqlClient.SqlParameter[] prmSQL
if (prmSQL != null)
{
while (i < prmSQL.Length)
{
sqlCommand.Parameters.Add(prmSQL[i]);
i = i + 1;
}
}
SqlDataReader sqlReader = sqlCommand.ExecuteReader();
For debugging my stored procedures I really need the string that sql management studio needs which is like
exec sp_name param one, param two (with quotes if needed for strings and dates..)
The sql command object does not provide this string via some property. The only way I know is to run the sql profiler on sql server and grab the string. Unfortunately the DBA's do not like this since they say running the profiler impacts performance. Is there any addin or code snippet you guys use to get the sp exec string from c# code ? Whats the best way to get this string ? Thanks
You could use a tool like mvc-mini-profiler available on NuGet (note: the name is misleading; it isn't limited to MVC). Minor clarification - since it wraps the connection, you would need to use the abstract DbConnection rather than SqlConnection, and then you just tweak the one line of code (probably in a utility class somewhere) that creates your connection, i.e. instead of:
var conn = new SqlConnection(someString);
return conn;
you might use:
var conn = new SqlConnection(someString);
return new StackExchange.Profiling.Data.ProfiledDbConnection(
conn, MiniProfiler.Current);
There's a couple of other steps to enable it (all shown on the site page), but it literally takes 2 minutes to add to an MVC application. The output is that it monitors, in real time, for enabled users (developers etc), all the activity. We use it 24x7 on stackoverflow/stackexchange (meaning: we made very sure it didn't impact performance). A live demo is available on https://data.stackexchange.com/ - just log in, and the profiling data is visible top-left. It automatically presents the data in a form runnable from SSMS, because that is how we often use it - so: it presents parameters as though they were variable declarations / initializations.
It also plays nicely with ORMs such as LINQ-to-SQL and dapper-dot-net (and many others).
Rep is too low (still a noob to StackOverflow)to comment so I'm posting this as an answer. My apologies. However, you might consider looking at SMO. SMO is a .NET object model that can be used to interact with SQL Server. Using SMO you can get a reference to a specific Stored Procedure
and then enumerate it's parameters.
That might help you get started.
In order to construct the EXEC command, you will need to know the parameter names used by the procedure. I believe you can find them by using the GetDbSchemaTable method, whcih will retrieve stored procedure SQL (I have done this using MS-Access/OLEDB and am assuming it works the same for MS-SQL/SqlClient):
using (conn == new OleDb.OleDbConnection(DBConnection)) {
conn.Open();
DataTable DBObject = conn.GetOleDbSchemaTable(OleDb.OleDbSchemaGuid.Procedures, null);
}
The column named "PROCEDURE_DEFINITION" contains the procedure's SQL and hopefully the parameter list.
You may also want to have a look at Obtaining Schema Information from a Database.
HTH

Inserting into DB with parameters safe from SQL injection?

I been reading a bit about SQL injection and I want to be sure my code is lets say "safe" from it, I was planning on using RegExp validators to check the user input but another post in here suggested only using parametrized querys, well I'm using them but I want to be sure my code is safe, is it?
using ( SqlConnection dataConnection = new SqlConnection(myConnectionString) )
{
using ( SqlCommand dataCommand = dataConnection.CreateCommand() )
{
dataCommand.CommandText = "INSERT INTO Lines (Name, CreationTime) " +
"VALUES (#LineName, #CurrentDateTime)";
dataCommand.Parameters.AddWithValue("#LineName", TextBox2.Text);
dataCommand.Parameters.AddWithValue("#CurrentDateTime", DateTime.Now.ToString());
dataConnection.Open();
//do other DB stuff
I chop the last part to make the post shorter, the rest is just trying and catching exceptions and closing db connection as well as providing user feedback on inserting successful.
Your code is fine, it is protected from injection because the values are passed as parameters not string literals. However, if you are writing this type of data access yourself, have you considered creating SqlParameter objects and explicitly setting the type, size etc, and adding the parameters to the command? AddWithValue will work just fine, but SQL Server will have to determine the type, a little, but unnecessary overhead.
Well, you could always try to inject a SQL statement into the textbox, that will probably give you a quicker, definite answer.
Yes, that's reasonably safe. So long as you don't use "sanitized" variables from a prepared statement to generate dynamic sql later, you're usually ok. The fact that you're using a prepared statement will take care of dealing with escape characters and other simple methods of injection.
I wouldn't forgo any other validation though...

Npgsql pass parameters by name to a stored function

I'm working with code I'm converting to Pgsql working with .NET. I want to call a stored function that has several parameters, but I'd like to bind the parameters by name, like so:
NpgsqlCommand command = new NpgsqlCommand("\"StoredFunction\"", _Connection)
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("param2", value2);
command.PArameters.Add("param1", value1);
Attempts to do this so far look for a function with parameter types matching in the order in which I added the parameters to the collection, not by name.
Is it possible for Npgsql to bind parameters to stored functions by name?
Currently Npgsql doesn't support pass parameters by name. Although it supports receiving out parameter values by name.
Would you mind to fill a bug report about that? So we can track and implement it.
Unfortunately it does not work with store procedure (CommandType.StoredProcedure).
It does with SQL-text command (CommandType.Text).
You can use :paramname, plus I think in the latest version you can use parameters.addwithvalue(":paramname", param).
You can also use #paramname with the latest version (like MS Sql Server).
Read section "Using parameters in a query " of this manual for an answer to your original question - but remember what I said above to make your life easier.

Why do I need OleDbCommand.Prepare()?

I'm working with a datagrid and adapter that correspond with an MSAccess table through a stored query (named "UpdatePaid", 3 paramaters as shown below) like so:
OleDbCommand odc = new OleDbCommand("UpdatePaid", connection);
OleDbParameter param;
odc.CommandType = CommandType.StoredProcedure;
param = odc.Parameters.Add("v_iid", OleDbType.Double);
param.SourceColumn = "I";
param.SourceVersion = DataRowVersion.Original;
param = odc.Parameters.Add("v_pd", OleDbType.Boolean);
param.SourceColumn = "Paid";
param.SourceVersion = DataRowVersion.Current;
param = odc.Parameters.Add("v_Projected", OleDbType.Currency);
param.SourceColumn = "ProjectedCost";
param.SourceVersion = DataRowVersion.Current;
odc.Prepare();
myAdapter.UpdateCommand = odc;
...
myAdapter.Update();
It works fine...but the really weird thing is that it didn't until I put in the odc.Prepare() call.My question is thus: Do I need to do that all the time when working with OleDb stored procs/queries? Why? I also have another project coming up where I'll have to do the same thing with a SqlDbCommand... do I have to do it with those, too?
This is called, oddly enough, a prepared statement, and they're actually really nice. Basically what happens is you either create or get a sql statement (insert, delete, update) and instead of passing actual values, you pass "?" as a place holder. This is all well and good, except what we want is our values to get passed in instead of the "?".
So we prepare the statement so instead of "?", we pass in parameters as you have above that are going to be the values that go in in place of the place holders.
Preparing parses the string to find where parameters can replace the question marks so all you have to do is enter the parameter data and execute the command.
Within oleDB, stored queries are prepared statements, so a prepare is required. I've not used stored queries with SqlDB, so I'd have to defer to the 2 answers previous.
I don't use it with SqlDbCommand. It seems as a bug to me that it's required. It should only be nice to have if you're going to call a procedure multiple times in a row. Maybe I'm wrong and there's a note in documentation about providers that love this call too much.
Are you using the JET OLEDB Provider? or MSDASQL + JET ODBC?
You should not need to call Prepare(), but I believe that's driver/provider dependent.
You definitely don't need to use Prepare() for System.Data.SqlClient.

Categories

Resources