Get stored procedure parameters by either C# or SQL? - c#

I was hoping to find an easy way to get a parameter list of a stored procedures parameters. If the procedure has 3 paramaters, I want a list like this:
param1
param2
param3
It would be best to be able to do this in C# Code, but SQL would suffice as well. Ideas?

select * from information_schema.parameters
where specific_name='your_procedure_name'
Also refer this post to know more methods
https://exploresql.com/2016/10/14/different-methods-to-get-parameter-list-of-a-stored-procedure/

For SQL Server this should work.
private void ListParms()
{
SqlConnection conn = new SqlConnection("my sql connection string");
SqlCommand cmd = new SqlCommand("proc name", conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
SqlCommandBuilder.DeriveParameters(cmd);
foreach (SqlParameter p in cmd.Parameters)
{
Console.WriteLine(p.ParameterName);
}
}

You can do this without ever touching SqlConnection, which I find is a bonus.
This uses the SqlServer.Management.Smo namespace, so you need a reference to Microsoft.SqlServer.ConnectionInfo, Microsoft.SqlServer.Management.Sdk, and Microsoft.SqlServer.Smo in your project.
Then use the following code:
Server srv = new Server("serverNameHere");
srv.ConnectionContext.AutoDisconnectMode = AutoDisconnectMode.NoAutoDisconnect;
srv.ConnectionContext.LoginSecure = false; //if using username/password
srv.ConnectionContext.Login = "username";
srv.ConnectionContext.Password = "password";
srv.ConnectionContext.Connect();
Database db = srv.Databases["databaseNameHere"];
foreach(StoredProcedure sp in db.StoredProcedures)
{
foreach(var param in sp.Parameters)
{
string paramName = param.Name;
var dataType = param.DataType;
object defaultValue = param.DefaultValue;
}
}

If you're familiar with Enterprise Library, there's a good method which allows to DiscoverParameters(), using the Data Access Application Block.
DbCommand command = new DbCommand();
command.CommandText = #"myStoredProc";
command.CommandType = CommandType.StoredProcedure;
Database database = new SqlDatabase(myConnectionString);
database.DiscoverParameters(command);
// ...
Some links that might help:
DiscoverParameters Method;
Microsoft.Practices.EnterpriseLibrary.Data Namespace.
The above links refers to EntLib 3.1. Depending on the .NET Framework version you're using, you might also consider downloading the correct EntLib version for you following this link.

Related

How to import Data in csv file into a SQL Server database using C#

I'm trying to import data into a SQL Server database from a .csv file. I have just one problem: for the money row, I am throwing Format.Exception due to wrong format of money variable.
I tried to convert to double I change the period instead of comma, I change in split(); method also semicolon ; instead of comma , but the exception didn't go away. Does anyone know what to do about this?
It is just an experiment.
My .csv file looks like this:
Database table's columns are:
name, second_Name, nickname, money
Code:
public void Import()
{
SqlCommand command = null;
var lineNumber = 0;
using (SqlConnection conn = DatabaseSingleton.GetInstance())
{
// conn.Open();
using (StreamReader reader = new StreamReader(#"C:\Users\petrb\Downloads\E-Shop\E-Shop\dataImport.csv"))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (lineNumber != 0)
{
var values = line.Split(',');
using (command = new SqlCommand("INSERT INTO User_Shop VALUES (#name, #second_Name, #nickname, #money", conn))
{
command.Parameters.Add(new SqlParameter("#name", values[0].ToString()));
command.Parameters.Add(new SqlParameter("#second_Name", values[1].ToString()));
command.Parameters.Add(new SqlParameter("#nickname", values[2].ToString()));
command.Parameters.Add(new SqlParameter("#money", Convert.ToDecimal(values[3].ToString())));
command.Connection = conn;
command.ExecuteNonQuery();
}
}
lineNumber++;
}
}
conn.Close();
}
Console.WriteLine("Products import completed");
Console.ReadLine();
}
I maintain a package Sylvan.Data.Csv that makes it very easy to bulk import CSV data into SQL Server, assuming the shape of your CSV file matches the target table.
Here is some code that demonstrates how to do it:
SqlConnection conn = ...;
// Get the schema for the target table
var cmd = conn.CreateCommand();
cmd.CommandText = "select top 0 * from User_Shop";
var reader = cmd.ExecuteReader();
var tableSchema = reader.GetColumnSchema();
// apply the schema of the target SQL table to the CSV data.
var options =
new CsvDataReaderOptions {
Schema = new CsvSchema(tableSchema)
};
using var csv = CsvDataReader.Create("dataImport.csv", options);
// use sql bulk copy to bulk insert the data
var bcp = new SqlBulkCopy(conn);
bcp.BulkCopyTimeout = 0;
bcp.DestinationTableName = "User_Shop";
bcp.WriteToServer(csv);
On certain .NET framework versions GetColumnSchema might not exist, or might throw NotSupportedException. The Sylvan.Data v0.2.0 library can be used to work around this. You can call the older GetSchemaTable API, then use the Sylvan.Data.Schema type to convert it to the new-style schema IReadOnlyCollection<DbColumn>:
DataTable schemaDT = reader.GetSchemaTable();
var tableSchema = Schema.FromSchemaTable(schemaDT);
Try this:
SqlParameter moneyParam = new SqlParameter("#money", SqlDbType.Money);
moneyParam.Value = SqlMoney(Convert.ToDecimal(values[3].ToString()))
command.Parameters.Add(moneyParam)
Not sure if it'll work, but it seems to make sense to me.
The problem being that when you use the constructor for the SQL parameter, I think it assumes the type of your variable, so in this case, as you're passing a double or whatever, the equivalent DB type is 'decimal', however your DB schema will be using the DB type 'money', so explicitly setting the DB type in your parameter constructor should help.

select query does not work with parameters using Parameters.AddWithValue

The following query in C# doesn't work, but I can't see the problem:
string Getquery = "select * from user_tbl where emp_id=#emp_id and birthdate=#birthdate";
cmdR.Parameters.AddWithValue("#emp_id", userValidate.emp_id);
cmdR.Parameters.AddWithValue("#birthdate", userValidate.birthdate);
OdbcCommand cmdR = new OdbcCommand(Getquery, conn);
OdbcDataReader Reader = cmdR.ExecuteReader();
Reader.HasRows returns no result but when I query it to my database I got data.
I'll assume your code is actually not quite as presented, given that it wouldn't currently compile - you're using cmdR before you declare it.
First, you're trying to use named parameters, and according to the documentation of OdbcCommand.Parameters, that isn't supported:
When CommandType is set to Text, the .NET Framework Data Provider for ODBC does not support passing named parameters to an SQL statement or to a stored procedure called by an OdbcCommand. In either of these cases, use the question mark (?) placeholder.
Additionally, I would personally avoid using AddWithValue anyway - I would use something like:
string sql = "select * from user_tbl where emp_id = ? and birthdate = ?";
using (var connection = new OdbcConnection(...))
{
connection.Open();
using (var command = new OdbcCommand(sql, connection))
{
command.Parameters.Add("#emp_id", OdbcType.Int).Value = userValidate.EmployeeId;
command.Parameters.Add("#birthdate", OdbcType.Date).Value = userValidate.BirthDate;
using (var reader = command.ExecuteReader())
{
// Use the reader here
}
}
}
This example uses names following .NET naming conventions, and demonstrates properly disposing of resources... as well as fixing the parameter issue.
I do think it's slightly unfortunate that you have to provide a name for the parameter when adding it to the command even though you can't use it in the query, but such is life.
Use like this:
string Getquery = "select * from user_tbl where emp_id=? and birthdate=?";
cmdR.Parameters.AddWithValue("#emp_id", userValidate.emp_id);
cmdR.Parameters.AddWithValue("#birthdate", userValidate.birthdate);
OdbcCommand cmdR = new OdbcCommand(Getquery, conn);
OdbcDataReader Reader = cmdR.ExecuteReader();
while(Reader.Read())
{
//Do something;
}
I know this thread is old, but I wanted to share my solution for anyone else coming up on this.
I was having issues with the typical method that Jon posted. I have used it before, but for some reason with this new string I had it was not wanting to actually place the parameter correctly and was causing the reader to not work.
I ended up doing something like this instead, since in the end we are just replacing parts of a string.
string sql = "select * from user_tbl where emp_id = "+ var1 +" and birthdate = "+
var2""
OdbcCommand command = new OdbcCommand(sql);
This was easier for me to get to work. Be warned though, I am not sure if it has any specific drawbacks when compare to using the command parameter method.

iDB2 Select command with parameters returning SQL0418

I'm developing a .NET application that connects to a DB2 iSeries 7.1 database, using the IBM.Data.DB2.iSeries.dll.
I need to do a SELECT command that has n parameters which are defined in the query as #paramX, setting the parameter values afterwards, but when I run the code I get a SQL048 Use of parameter marker not valid.. I've searched everywhere for documentation / examples but everything I've read is in par with the code I'm using. Am I missing something? If this is not valid, what is the best alternative?
This is the isolated code I'm using to test.
static void Main(string[] args)
{
String myConnectionString = "DataSource=*******;Database=*******;UserId=*******;Password=*******;";
iDB2Connection myConnection = new iDB2Connection();
try{
myConnection.ConnectionString = myConnectionString;
myConnection.Open();
var cmd = new iDB2Command("SELECT TIMESTAMP(DATE(#param0),TIME(#param1)) FROM SYSIBM.SYSDUMMY1", myConnection);
cmd.Parameters.Add(new iDB2Parameter("#param0", iDB2DbType.iDB2Char));
cmd.Parameters["#param0"].Value = "1900-01-01";
cmd.Parameters.Add(new iDB2Parameter("#param1", iDB2DbType.iDB2Char));
cmd.Parameters["#param1"].Value = "00.00.00";
using (var reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
reader.Read();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < reader.FieldCount; i++)
{
sb.AppendLine(reader[i].ToString().Trim());
}
Console.Out.WriteLine(sb.ToString());
}
}
}catch(Exception e)
{
Console.Out.WriteLine(e.ToString());
}finally{
if (myConnection != null)
{
myConnection.Close();
}
}
Console.Read();
}
EDIT
In an unrelated answer I've found that the problem might be that DB2 doesn't know the underlying type of the parameter (which is strange since I'm strong typing it), thus, a possible solution is to do a cast in the query to the expected param type, as such:
SELECT TIMESTAMP(DATE(cast(#param0 as char(10))),TIME(cast(#param1 as char(10)))) FROM SYSIBM.SYSDUMMY1
This actually worked but, isn't there any better way to handle this?
AFAIK, this is a platform limitation. that can be confirmed by an explanation that the platform adds to the application exception*. That being said, as I can't change the parameters I receive and don't have access to the info they are going to held in the query, the best solution to my specific problem is to do a CAST to the types that the TIMESTAMP scalar function uses, e.g.:
SELECT TIMESTAMP(cast(#param0 as DATE),cast(#param1 as TIME)) FROM SYSIBM.SYSDUMMY1

Oracle Entity Framework passing parameter to command text

i have a table test
CREATE TABLE TEST
(
ID NUMBER,
NAME VARCHAR2(30 BYTE)
)
CREATE OR REPLACE TRIGGER test_trigger
BEFORE INSERT
ON test
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT test_sequence.nextval INTO :NEW.ID FROM dual;
END;
ALTER TABLE TEST ADD (
PRIMARY KEY
(ID)
Now I want to insert from a page with values from textbox.
The code is given below
protected void ASPxButton1_Click(object sender, EventArgs e)
{
//string name = Convert.ToString(ASPxTextBox1.Text);
int retVal = 0;
string providerName = "Oracle.DataAccess.Client";
string constr =
#"User Id=scott;Password=tiger;Data Source=orcl;enlist=true";
// Get the provider factory.
DbProviderFactory factory = DbProviderFactories.GetFactory(providerName);
try
{
using (scope txn = new scope())
{
using (DbConnection conn1 = factory.CreateConnection())
{
conn1.ConnectionString = constr;
conn1.Open();
// Create a command to execute the sql statement.
DbCommand cmd1 = factory.CreateCommand();
cmd1.Connection = conn1;
cmd1.CommandText = #"insert into test ( [NAME] ) values (:name)";
//OracleParameter Nameprm = cmd1.Parameters.Add("name" , OracleDbType.Varchar2, 10 );
//Nameprm.Direction = ParameterDirection.Input;
//Nameprm.Value = ASPxTextBox1;
var name = Convert.ToString(ASPxTextBox1);
var parameter = factory.CreateParameter();
parameter.DbType = System.Data.DbType.String;
parameter.ParameterName = "#name";
parameter.Value = name;
cmd1.Parameters.Add(parameter);
retVal = cmd1.ExecuteNonQuery();
//Console.WriteLine("Rows to be affected by cmd1: {0}", retVal);
// Close the connection and dispose the command object.
conn1.Close();
conn1.Dispose();
cmd1.Dispose();
}
txn.SaveChanges();
}
}
catch (Exception ex)
{
throw;
}
}
}
But i am always getting ORA-00928: missing SELECT keyword. but if i give values directly then its inserting data. I am trying to solve it in many ways still no luck. Your help will be very much appreciated as i am stuck here. Thank you in advance.
#competent_tech 's answer looks good, as an additional thought:
In my last job-but-one we used a massive Oracle database for all our persistence, and I had no end of grief with this sort of problem. Most of them were solved when I stopped using the built-in ADO.Net drivers and used the Oracle provided drivers (as recommended by Microsoft here).
You can get the Oracle Data Provider for .Net (ODP.Net) for your version of Oracle here.
If you're already using the ODP.Net my sincere apologies, it's a little hard to tell from the code snippet :)
If the name isn't the problem, then it may be with the parameter type (OracleDBType.VarChar2, although this should be inferred for you by DbType) or the parameter direction (ParameterDirection.InputOnly parameter?)
I hope that might help :)
I don't think that your parameter name is correct.
Try changing:
parameter.ParameterName = "#name";
to
parameter.ParameterName = "name";

How to prevent a SQL Injection escaping strings

I have some queries (to an acccess database) like this :
string comando = "SELECT * FROM ANAGRAFICA WHERE E_MAIL='" + user + "' AND PASSWORD_AZIENDA='" + password + "'";
and I'd like to "escape" user and password, preventing an injection.
How can I do it with C# and .NET 3.5? I'm searching somethings like mysql_escape_string on PHP...
You need to use parameters. Well dont have to but would be preferable.
SqlParameter[] myparm = new SqlParameter[2];
myparm[0] = new SqlParameter("#User",user);
myparm[1] = new SqlParameter("#Pass",password);
string comando = "SELECT * FROM ANAGRAFICA WHERE E_MAIL=#User AND PASSWORD_AZIENDA=#Pass";
Don't escape the strings to start with - use a parameterized query. Benefits of this over escaping:
The code is easier to read
You don't have to rely on getting the escaping correct
It's possible that there are performance improvements (DB-specific etc)
It separates "code" (the SQL) from the data, which is just good sense logically
It means you don't need to worry about data formats for things like numbers and dates/times.
The docs for SqlCommand.Parameters give a good, complete example.
You should use the SQL paramters to prevent SQL Injection
look at the code
//
// The name we are trying to match.
//
string dogName = "Fido";
//
// Use preset string for connection and open it.
//
string connectionString = ConsoleApplication716.Properties.Settings.Default.ConnectionString;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
//
// Description of SQL command:
// 1. It selects all cells from rows matching the name.
// 2. It uses LIKE operator because Name is a Text field.
// 3. #Name must be added as a new SqlParameter.
//
using (SqlCommand command = new SqlCommand("SELECT * FROM Dogs1 WHERE Name LIKE #Name", connection))
{
//
// Add new SqlParameter to the command.
//
command.Parameters.Add(new SqlParameter("Name", dogName));
//
// Read in the SELECT results.
//
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
int weight = reader.GetInt32(0);
string name = reader.GetString(1);
string breed = reader.GetString(2);
Console.WriteLine("Weight = {0}, Name = {1}, Breed = {2}", weight, name, breed);
}
}
}
Yes, you can avoid injection by using Named Parameters
Use parameters instead of escaping strings:
var comando = "SELECT * FROM ANAGRAFICA WHERE E_MAIL=#user AND PASSWORD_AZIENDA=#password";
Then assign values to those parameters before you execute the SqlCommand.
You can check the below link to know how to prevent SQL injection in ASP.Net. I would prefer to use
Using parametrized queries or Stored Procedures.
Validating special characters like '(very dangerous)
http://dotnet.dzone.com/news/aspnet-preventing-sql-injectio
If you can convert these to Named Parameters, I think you would be better served.
#Jethro
You could also write it like this:
SqlParameter[] sqlParams = new SqlParameter[] {
new SqlParameter("#Name", contact.name),
new SqlParameter("#Number", contact.number),
new SqlParameter("#PhotoPath", contact.photoPath),
new SqlParameter("#ID", contact.id)
};
Follow the steps below and resolve the SQL INJECTION problem:
OracleParameter[] tmpParans = new OracleParameter[1];
tmpParans[0] = new Oracle.DataAccess.Client.OracleParameter("#User", txtUser.Text);
string tmpQuery = "SELECT COD_USER, PASS FROM TB_USERS WHERE COD_USER = #User";
OracleCommand tmpComand = new OracleCommand(tmpQuery, yourConnection);
tmpComand.Parameters.AddRange(tmpParans);
OracleDataReader tmpResult = tmpComand.ExecuteReader(CommandBehavior.SingleRow);

Categories

Resources