I am mostly new to c# so i am looking for some guidance here. I am testing a method that i need to pass a list of guids to and run a stored procedure that returns values based on the guids i pass to it which i can then print to the console. I can get the method to work when i pass only one guid but when i pass a list of guids it seems to not work.
I feel like i am lacking some understanding here around how i should pass the list of guids and return it. I get conversion errors trying to return List.
Here is how far i have got but i feel like i am stuck now and cant progress anymore from any info i have found online.
class Program
{
static void Main(string[] args)
{
List<Guid> tempguid = new List<Guid>();
tempguid.Add(Guid.Parse("472USFA0-B705-9A73-ABD4-3B1870AF1409"));
tempguid.Add(Guid.Parse("FA97E6BB-0875-5UB9-967A-87ECC396F9F0"));
GetValue(tempguid);
Console.WriteLine(GetValue);
}
public void GetValue(List<Guid> tempguid)
{
using (SqlConnection conn = new SqlConnection("connection string here"))
{
conn.Open();
SqlCommand cmd = new SqlCommand("stored procedure here", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#id", tempguid));
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine((string)rdr["value"]);
}
Console.ReadLine();
}
}
}
}
Should i be passing the list like this GetValue(List tempguid)?
EDIT
ok so if i use a TVP.
Something like:
CREATE TYPE [dbo].[Identity] AS TABLE(
[Id] [uniqueidentifier] NOT NULL
)
GO
Then my procedure will look something along the lines of:
CREATE OR ALTER PROCEDURE [dbo].[procedure_name]
#id dbo.Identity READONLY
as
SELECT t.[id]
,t.[value]
FROM [dbo].[table1] t
Inner Join #id i on i.Id = t.id
How do i use this TVP in c# for my stored procedure?
you need a foreach loop on GUID list. Try like:
foreach (var g in tempguid)
{
cmd.Parameters.Add(new SqlParameter("#id", g));
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine((string)rdr["value"]);
}
Console.ReadLine();
}
cmd.Parameteres.Clear();
}
You can't pass a list to sp. You need to convert your guids into a csv string example:
var param = string.Join(", ", tempguid);
Then
cmd.Parameters.Add(new SqlParameter("#id", param));
Then after receiving your parameter on the sp pass into String_Split. Goodluck!
Passing values to TVPs from ADO .NET is very straightforward, and requires very little extra code compared to passing data to regular parameters.
For the data type you specify SqlDbType.Structured.
You specify the name of the table type in the TypeName property of the parameter.
You set the Value property of the parameter to something suitable.
As mentioned in the above link System.Data.SqlClient supports populating table-valued parameters from DataTable, DbDataReader or IEnumerable<T> \ SqlDataRecord objects.
If you already have the list of Guids coming from other sources in your case tempguid then you could use a datatable to pass the details to stored procedure.
DataTable tvp = new DataTable();
tvp.Columns.Add(new DataColumn("Id", typeof(Guid)));
// populate DataTable from your List here
foreach (var id in tempguid)
tvp.Rows.Add(id);
And change the ADO.NET code like below -
conn.Open();
SqlCommand cmd = new SqlCommand("dbo.tvpProcedure", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParameter = new SqlParameter();
tvpParameter.ParameterName = "#id";
tvpParameter.SqlDbType = System.Data.SqlDbType.Structured;
tvpParameter.Value = tvp;
tvpParameter.TypeName = "dbo.testTVP";
cmd.Parameters.Add(tvpParameter);
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine((string)rdr["value"]);
}
Console.ReadLine();
}
Side notes:
Looks like the GUIDs you have shown in the code seems invalid as they contain non-
hexadecimal values.
472USFA0-B705-9A73-ABD4-3B1870AF1409
^^
FA97E6BB-0875-5UB9-967A-87ECC396F9F0
^
Change the Type name something meaningful instead of dbo.Identity in my case I used
dbo.testTVP
Further information -
http://www.sommarskog.se/arrays-in-sql-2008.html
Related
I have a web service in C#, I use it to consults from tables, but I want to create a WebMethod to call a stored procedure and get back multiples output parameters. I can execute it with output parameters, it doesn't work when I try to call it whit outputs parameters.
This is a sample, I want to get back more that 2 parameters.
Stored procedure:
CREATE OR REPLACE PROCEDURE O_CAPEREZ.GIO_SP (
VNOMBRE IN VARCHAR2,
SALUDO OUT VARCHAR2 )
AS
BEGIN
INSERT INTO G_PRUEBA_SP(NOMBRE)
VALUES (vNOMBRE);
SALUDO:= ('Hello: ' || vNOMBRE);
END;
And this is my code in the web service, when I execute it using output variables I get this error
[HYC00] [Oracle][ODBC]Optional feature not implemented
C# code:
[WebMethod]
public string AP_Data(string curp)
{
string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
using (OdbcConnection con = new OdbcConnection(constr))
{
OdbcCommand cmd = new OdbcCommand("{CALL GIO_SP(?,?)}", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#vNOMBRE", (curp));
cmd.Parameters.Add("#vNOMBRE", OdbcType.VarChar, 18);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
cmd.Parameters["#SALUDO"].Direction = ParameterDirection.ReturnValue;
cmd.Connection.Close();
string ret = Convert.ToString(cmd.Parameters["#SALUDO"].Value);
return ret;
}
}
You have to add the parameter to the list even if you're not going to set a value there:
cmd.Parameters.Add("#SALUDO", OdbcType.VarChar, 18).Direction = ParameterDirection.Output;
I don't know the the Oracle flavor is different, but in SQL I use ParameterDirection.ReturnValue rather than ParameterDirection.Output.
here's how i do it in MS SQL server 2008 But notice the data type and the lenth of the variables your create must be the same in your table
the stored proc create code
USE DATABASE DATABASE_NAME
GO
CREATE PROC SP_METHOD
#ID_CATIGORY INT,
#NAME VARCHAR (50),
#DESCRIPTION VARCHAR (50)
AS
INSERT INTO TABLE_NAME
([ID_CAT]
,[NAME_PRODUCT]
,[DESC_PRODUCT]
)
VALUES
( #ID_CATIGORY
,#NAME
,#DESCRIPTION )
GO
in the c# code
// Create SqlConnection
SqlConnection conn= new SqlConnection(#"Server=server_name;
DataBase=your_data_base_name;Integrated Security=false;User
Id=user_id;Password=password");
// Open the Connection
if (sqlconnection.State != ConnectionState.Open)
{
conn= .Open();
}
// execute stored_procedure method don't change this
public void ExecuteCommand(string stored_procedure, SqlParameter[] param)
{
SqlCommand sqlcomd = new SqlCommand();
sqlcomd.CommandType = CommandType.StoredProcedure;
sqlcomd.CommandText = stored_procedure;
sqlcomd.Connection = sqlconnection;
if (param !=null)
{
sqlcomd.Parameters.AddRange(param);
}
sqlcomd.ExecuteNonQuery();
}
// close connection method
public void close_conn()
{
if (sqlconnection.State == ConnectionState.Open)
{
sqlconnection.Close();
}
}
// execute and retrieving data Method
public void Add_product(int ID_cat ,string Name_Product,string
Des_Product)
{
SqlParameter[] param = new SqlParameter[3];
param[0] = new SqlParameter("#ID_CAT", SqlDbType.Int);
param[0].Value = ID_cat;
param[1] = new SqlParameter("#NAME_PRODUCT", SqlDbType.VarChar, 50);
param[1].Value = Name_Product;
param[2] = new SqlParameter("#DESC_PRODUCT", SqlDbType.VarChar, 50);
param[2].Value = Des_Product;
ExecuteCommand("StoredProcedure_name", param);
close_conn();
}
and finally you can call this function
Add_product(Convert.ToInt32(ComboBox.SelectedValue),txt_name.Text,
txt_desc.Text);
if there is any part you don't understand lemme know
I've seen many ways to accomplish this.
One way is to Pipe Delimit your select statement in your stored procedure and then use "Value1|Value2".Split('|')[0] to get Value1.
You could also return a table instead of using multiple parameters
DataTable table = new DataTable();
DataAdapter adapter = new DataAdapter(cmd);
adapter.fill(table);
return table.Rows[0]["Greeting"] + table.Rows[0]["Name"];
In the second example you can return as many 'Parameters' as you want, but you will have to assign them to their rightful spots later in your code.
I've also seen an XML way to do this same feature but I won't provide the code here since I don't personally think it is a very good way to do it. The way I've seen done was adding a bunch of XML attributes to a parent tag, and then coming back later and finding the value of each tag later in the code.
In MYSQL it would go like this
CREATE PROCEDURE O_CAPEREZ.GIO_SP (
#vNOMBRE VARCHAR(50))
AS
BEGIN
INSERT INTO G_PRUEBA_SP(NOMBRE)
VALUES (#vNOMBRE);
select 'Hola' as Greeting, #vNOMBRE as Name
END
Also note what Marc_s commented
You need to set the .Direction of the parameter BEFORE making the call to .ExecuteNonQuery()
From C# Code, I'm trying to call a PACKAGE.PROCEDURE() from Oracle. In this simple example I should get one value from the procedure call, but all I get is error:
wrong number or types of arguments in call to 'RETURN_NUM'
The procedure is declared as follows:
PROCEDURE return_num(xNum OUT NUMBER) AS
BEGIN
xNum:= 50;
dbms_output.put_line('hello world ' || xNum);
END;
C# code:
Oraclecon.Open();
OleDbCommand myCMD = new OleDbCommand("TEST.return_num", Oraclecon);
myCMD.CommandType = CommandType.StoredProcedure;
myCMD.Parameters.Add("xNum", OleDbType.Numeric);
OleDbDataReader myReader;
myReader = myCMD.ExecuteReader();
Can some one please point out what I'm doing wrong. Then in a real scenario I would like to call a procedure that returns a set of values from a custom Type, such as:
TYPE r_interface_data IS RECORD
(
object_id VARCHAR2(16),
obj_type VARCHAR2(32)
);
TYPE t_interfase_data IS TABLE OF r_interface_data;
How can I approach that. Thanks!
UPDATE: In my particular case I ended-up doing the following approach
using (OleDbCommand cmd = new OleDbCommand("PACKAGE.procedure_name"))
{
cmd.CommandType = CommandType.StoredProcedure;
SqlManager sqlManager = new SqlManager();
return sqlManager.GetDataSet(cmd);
}
I don't think you're that far off... try this:
OracleCommand cmd = new OracleCommand("return_num", Oraclecon);
cmd.Parameters.Add(new OracleParameter("xNum", OracleDbType.Decimal,
ParameterDirection.Output));
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
OracleDecimal d = (OracleDecimal)cmd.Parameters[0].Value;
double result = d.ToDouble();
result now contains the out parameter from the procedure.
I think your problem is you were attempting to use a DbDataReader on a stored procedure. DbDataReader is for queries.
Also, I used ODP.net -- that may or may not have contributed to your issue, that you were using Ole.
I want the user to select the search criteria for his books here is code, suggestions please!!
String keyword=Textbox1.Text; //User types keyword
String userCriteria=Textbox2.Text;// Can be Title, Author, Subject or ISBN;
String sql="Select * from tableBooks WHERE '"+keyword+"' like '%"+userCriteria+"'%";
How to let the user select their own criteria for searching the database?
You certainly need a better way to build your query.
You do not directly take input from the user without certain measure of checking or filtering and put it in your query. That would expose your application to sql injections.
Use SQL parameters.
Try this link as reference :http://www.dotnetperls.com/sqlparameter
example :
using (SqlCommand command = new SqlCommand("Select * from tableBooks WHERE #Field LIKE #Value", connection))
{
//
// Add new SqlParameter to the command.
//
command.Parameters.Add(new SqlParameter("Field", Textbox1.Text)); // I do not recommend using a textbox and letting the user write anything. You have to limit his choices by the fields in your table. Use a dropdownlist and limit his choices by meaningful fields in your "tableBooks" table.
command.Parameters.Add(new SqlParameter("Value", Textbox2.Text));
//
// Read in the SELECT results.
//
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
//GET YOUR BOOK
}
}
Please notice my comments :
// I do not recommend using a textbox and letting the user write anything as a "keyword". You have to limit his choices by the columns in your table. Use a dropdownlist and limit his choices by meaningful choices from your "tableBooks" table.
It is more secure to used parameterized query than the form you use already
you can try this, I think it will help
// Declare a connection
conn = new
SqlConnection("Server=.;DataBase=DataBase;Integrated Security=SSPI");
conn.Open();
//Create parameterized query
SqlCommand cmd = new SqlCommand(
"Select * from tableBooks WHERE (case #userCriteria when 'Title' then Title when 'Author' then Author when 'Subject' then Subject when 'ISBN' then ISBN else '' end) LIKE '%'+#keyword+ '%'", conn);
//Create parameter userCriteria
SqlParameter param = new SqlParameter();
param.ParameterName = "#userCriteria";
param.Value = userCriteria;
//Create parameter keyword
SqlParameter param = new SqlParameter();
param.ParameterName = "#keyword";
param.Value = userCriteria;
// add new parameter to command object
cmd.Parameters.Add(param);
// get data stream
reader = cmd.ExecuteReader();
// write each record
while(reader.Read())
{
//Get data
}
I'm writing a general purpose function for feeding query string straight into a sproc. The algorithm is fairly basic - loop through query keys, use them as parameter names while the value are used as parameter values. So it looks like something like this:
ArrayList pars = new ArrayList();
SqlParameter p;
int tryInt;
for (int i = 0; i < req.QueryString.Count; i++)
{
key = req.QueryString.AllKeys[i];
if (int.TryParse(req[key], out tryInt))
{
p = new SqlParameter("#" + key, SqlDbType.Int);
p.Value = tryInt;
pars.Add(p);
}
}
This works fine so far, except that of course all query keys must match the parameters for the sproc, if they don't I get an SQL exception saying something like
#someParameter is not a parameter for procedure some_sproc
But I need to be able to pass in variables in the query string that won't be passed into the sproc, so I need a way to "ignore" them.
Is there a way to test whether a given stored procedure expects a certain parameter? So that I can do something along these lines
if (paramExists("#" + key, "some_sproc") && int.TryParse(req[key], out tryInt))
{
p = new SqlParameter("#" + key, SqlDbType.Int);
p.Value = tryInt;
pars.Add(p);
}
You can use SqlCommandBuilder to get SP parameters:
using (SqlConnection sqlConn = new SqlConnection(yourConnStr))
using (SqlCommand sqlCmd = new SqlCommand(yourProcedureName, sqlConn))
{
sqlConn.Open();
sqlCmd.CommandType = CommandType.StoredProcedure;
SqlCommandBuilder.DeriveParameters(sqlCmd);
// now you can check parameters in sqlCmd.Parameters
}
More details here
you can interrogate the ANSI information_schema.parameters view, it returns all parameters with their position
SELECT parameter_name, ordinal_position FROM INFORMATION_SCHEMA.parameters
WHERE SPECIFIC_NAME = 'some_sproc'
Most DBs store "metadata" such as the structure of stored procedures in accessible system tables/views. If you're using MSS, I would look at sys.procedures and sys.parameters; join these two views and filter by procedure name.
I'm using C# in VS 2005 (.NET 2.0) and SQL Studio 2005 on an older CMS made in the mid-'00s. I'm tasked with creating a new permission gate that allows only certain users to see certain parts of the site.
I need help populating a List list based on feedback I got when I posted this question: Populate ArrayList from Stored Procedure result set
So, now, how do get get the values from the stored procedure into a List? I realize this is a novice question but I'm a novice...
Any help is greatly appreciated.
Assuming you are getting your results from a DataReader, all you have to do is read each row to add the value to a list.
List<int> ReadList(IDataReader reader)
{
List<int> list = new List<int>();
int column = reader.GetOrdinal("MyColumn");
while (reader.Read())
{
list.Add(reader.GetInt32(column));
}
return list;
}
Remember to dispose of the DataReader when you are done with it.
You can try using the model located on this MSDN page under Using Parameters with a SqlCommand and a Stored Procedure. The example is shown here:
static void GetSalesByCategory(string connectionString, string categoryName)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
// Create the command and set its properties.
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText = "SalesByCategory"; //Stored Procedure Name
command.CommandType = CommandType.StoredProcedure;
// Add the input parameter and set its properties.
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "#CategoryName";
parameter.SqlDbType = SqlDbType.NVarChar;
parameter.Direction = ParameterDirection.Input;
parameter.Value = categoryName;
// Add the parameter to the Parameters collection.
command.Parameters.Add(parameter);
// Open the connection and execute the reader.
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
//Instead of displaying to console this is where you would add
// the current item to your list
Console.WriteLine("{0}: {1:C}", reader[0], reader[1]);
}
}
else
{
Console.WriteLine("No rows found.");
}
reader.Close();
}
}
it depends on how you have retreived the results
reader?
dataset?
something else?
walk through the results using
foreach (int item in object...) {
List.Add(item);
}
or possibly (I dont remember the exact DataRow syntax off the top of my head...)
foreach (datarow row in object.table[0].rows) {
List.Add(row[0]);
}
IList<int> myInts = new List<int>();
using (IDbConnection connection = new SqlConnection("yourConnectionStringGoesHere"))
{
using (IDbCommand command = new SqlCommand("spName", connection))
{
command.CommandType = CommandType.StoredProcedure;
//command.Parameters.Add(...) if you need to add any parameters to the SP.
connection.Open();
using (IDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
myInts.Add(Int32.Parse(reader["someIntField"].ToString()));
}
}
}
Since you already have the table the idea would be to iterate over that table while adding the IDs of the vendor into a list.
List<VendorID_Data_Type> myList = new List<VendorID_Data_Type>();
foreach(DataRow r in GetAllVendors().Rows)
{
myList.Add(r["VendorID"]);
}
What I ended up doing is using a DataTable as an intermediary data type, which is populated by the stored procedure. Then, refactoring the DataTable as the data-source in a foreach loop, I populated the List. I needed to open a second question to get to this conclusion: 2-Column DataTable to List<int> .NET 2.0