C# SQL stored procedure call values - c#

Trying to communicate with the database, I am little bit confused about how to pass a value as a parameter(for ex. an itemID) and get back the records that are having this ID.
Here is my stored procedure:
ALTER PROCEDURE [dbo].[sp_lightItem]
(
#itemID INT
)
AS
BEGIN
SELECT [itemID],
[itemName],
[itemLocation],
[itemChBy]
FROM [dbo].[Item]
WHERE itemSystemType='E' and itemID=#itemID ORDER BY itemID DESC;
END
And this is my c# code so far..
public string LoadItemNew(int ItemID)
{
var acf = new AcFunctions();
var newstorevalue = SqlHelper.ExecuteDataset(acf.AcConn(), "sp_lightItem", ItemID);
}
As you can see in stored procedure, what I want is to get back those 4 elements:
[itemID],[itemName],[itemLocation],[itemChBy]
Unfortunately I do not know how to get them back/how to call them in c# function.
Any help is welcome.

i dont have enough repo to comment , can you provide the definition of
AcFunctions();
i am sure you it must be returning ConnectionString
try this
public string LoadItemNew(int ItemID)
{
var acf = new AcFunctions();
var newstorevalue = SqlHelper.ExecuteDataset(acf.AcConn(), "sp_lightItem", new SqlParameter ("#itemID",ItemID));
}
Edit 1
try this
public string LoadItemNew(int ItemID)
{
List<string> testList = new List<string>();
var acf = new AcFunctions();
var newstorevalue = SqlHelper.ExecuteReader(acf.AcConn(), "sp_lightItem", new SqlParameter ("#itemID",ItemID));
if(newstorevalue.HasRows)
{
while(newstorevalue.Read())
{
testList.Add(newstorevalue["itemID"].ToString());
testList.Add(newstorevalue["itemName"].ToString());
testList.Add(newstorevalue["itemLocation"].ToString());
testList.Add(newstorevalue["itemChBy"].ToString());
}
}
}

You can try with this approach, I will use Data Transfer Object for holding data retrieved from database and Execute DataReader for reading.
First of all, you need to create a DTO class, I will call it LightItemDTO
public class LightItemDTO
{
public int Id { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public string ChangedBy { get; set; }
}
Note: How to know the type of properties, you can reference this link: SQL Server Data Type Mappings
And now, I will using ADO.NET for execute the stored procedure to get data from database
public IEnumerable<LightItemDTO> GetLightItem(string itemText, string sqlConnectionString)
{
var results = new List<LightItemDTO>();
using (var con = new SqlConnection(sqlConnectionString))
{
using (var cmd = new SqlCommand("sp_lightItem", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ItemID", SqlDbType.VarChar).Value = itemText;
con.Open();
using (var reader = cmd.ExecuteReader())
{
results.Add(new LightItemDTO
{
Id = Convert.ToInt32(reader["itemID"]),
Name = reader["itemName"].ToString(),
Location = reader["itemLocation"].ToString(),
ChangedBy = reader["itemChBy"].ToString()
});
}
}
}
return results;
}
Using DataReader is the best practice with high performance.
ADO.NET is the manual way to achieve this task, you can use some ORM framework for do it easier, such as: Entity Framework, Dapper.NET ...

You could execute stored procedure with parameters in following:
using (SqlConnection con = new SqlConnection(dc.Con)) {
using (SqlCommand cmd = new SqlCommand("sp_lightItem", con)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ItemID", SqlDbType.VarChar).Value = itemId.Text;
con.Open();
cmd.ExecuteNonQuery();
}
}

first of all set the Commandtype as stored procedure and that procedure will return some data which you will save in dataset and then return the data set to where ever you want to populate the data
public DataSet LoadItemNew(int ItemID)
{
var acf = new AcFunctions();
return DataSet ds = SqlHelper.ExecuteDataset(acf.AcConn(),CommandType.StoredProcedure, "sp_lightItem",new SqlParameter("#itemID" ItemID);
}

You can try like this ..
public string LoadItemNew(int ItemID)
{
var acf = new AcFunctions();
List<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter("#itemID", ItemID));
DataSet Ds = SqlHelper.ExecuteDataset(acf.AcConn(),CommandType.StoredProcedure, "sp_lightItem" , parameters.ToArray());
return "ok";
}

Related

Can't Get Byte Array from SQL database using Enterprise Library

I'm working on a web API using Enterprise Library 5.0.505 AND I'm having trouble getting a byte array from a database. My insert statement works just fine using DbType.Binary but when I try to return it using SqlStringAccessor it comes up null.
I've tried researching it but most posts use a reader and my project doesn't allow for that route.
My Get method:
public IEnumerable<User> UserSearch(string username)
{
string sql = "SELECT * FROM Users WHERE Username = #Username";
var accessor = Database.CreateSqlStringAccessor<User>(sql, new NamedParameterMapper("#Username"));
return accessor.Execute(username);
}
The properties of my User type:
public int UserId { get; set; }
public string Username { get; set; }
public byte[] SaltedAndHashedPassword { get; set; }
public byte[] Salt { get; set; }
public bool LoggedIn { get; set; }
The Insert code I have that works correctly:
using (DbCommand cmd = Database.GetStoredProcCommand("[HeadCount_Ver01].[dbo].[AddUser]"))
{
Database.AddInParameter(cmd, "#Username", DbType.String, user.Username);
Database.AddInParameter(cmd, "#SaltedAndHashedPassword", DbType.Binary, user.SaltedAndHashedPassword);
Database.AddInParameter(cmd, "#Salt", DbType.Binary, user.Salt);
return Database.ExecuteNonQuery(cmd) > 0;
}
Any help is really appreciated, thanks.
It's been awhile since I've done this but if I remember correctly one of the easier ways was to use the SqlDbType.Binary as an output parameter then simply pull the value with a query.
The code below is untested and modified from another example using this method. The conversion from a SqlDbType.Binary to a byte array might need some attention or modification but should be really close.
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand("select #bytearray = dbcolumn from table", conn))
{
SqlParameter outputByteParam = new SqlParameter("#bytearray", SqlDbType.Binary)
{
Direction = ParameterDirection.Output
};
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(outputByteParam);
conn.Open();
cmd.ExecuteNonQuery();
byte[] result = outputByteParam.GetValueOrDefault<byte[]>(); // this line might need attention
}

C# Read multiple rows from different columns sharing same Foreign key SQL

I want an efficient way to retrieve all info that shares the same Foreign key in a table, and store the data in list/array.
I can read several rows from one column:
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
int idForeignKey = inputIdFkey //Implemented on the WebPage for testing purposes
List<string> result = new List<string>();
string oString = "Select Column from Table where foreignKey = #fKey";
conn.Open();
SqlCommand oCmd = new SqlCommand(oString, conn);
oCmd.Parameters.AddWithValue("#fKey", idForeignKey);
using (SqlDataReader oReader = oCmd.ExecuteReader())
{
while (oReader.Read())
{
result.Add(oReader.GetString(0));
}
}
conn.Close();
And I can read several columns if I am targeting one specific row:
int sqlData1;
int sqlData2;
int sqlData3;
string oString = "Select * from Table where TableID = #tId";
SqlCommand oCmd = new SqlCommand(oString, conn);
oCmd.Parameters.AddWithValue("#tId", 1001);
conn.Open();
using (SqlDataReader oReader = oCmd.ExecuteReader())
{
while (oReader.Read())
{
sqlData1 = oReader["Row1"].ToString();
sqlData2 = oReader["Row2"].ToString();
sqlData3 = oReader["Row3"].ToString();
}
}
conn.Close();
But I would love to be able to read all/specific data that has the same foreign key. So I want to be able to retrieve several rows, save them to a list, and retrieve several other row data from a different column that shares the same foreign key.
I imagine it to be something like this:
int idForeignKey = inputIdFkey //Implemented on the WebPage for testing purposes
List<int> intList = new List<int>();
List<string> stringList = new List<string>();
List<DateTime> dateList = new List<DateTime>();
string oString = "Select * from Table where ForeignKey = #fKey";
conn.Open();
SqlCommand oCmdSleep = new SqlCommand(oString, conn);
oCmdSleep.Parameters.AddWithValue("#fKey", idForeignKey);
using (SqlDataReader oReader = oCmdSleep.ExecuteReader())
{
while (oReader.Read())
{
intList.Add(oReader["Column1"].GetDateTime(0));
dstringList.Add(oReader["Column3"].GetDateTime(0));
dateList.Add(oReader["Column4"].GetDateTime(0));
}
}
conn.Close();
But this does not working... Please advice me
If you use something like Dapper it would simplify mapping your query result to List<T>.
Add Dapper to your project using nuget.
Install-Package Dapper -Version 1.50.5
Add using for Dapper at the top of your class where you are running the query.
using Dapper;
Add a class that matches the structure of your query results. There are ways to do this using a script or utility app. Here's an app for that.
public class MyClass
{
public int MyId { get; set; }
public string MyName { get; set; }
public DateTime MyDateTime { get; set; }
}
Then where you run the query do so like this.
using (conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
{
var MyList = conn.Query<MyClass>(#"select * from Table where ForeignKey = #fKey",
new { fKey = "SomeKey" }).ToList();
}
Once the query runs, you can then iterate across MyList.
foreach (var myItem in MyList)
{
// Do something with myItem
}
If you want to bind the results, simply remove .ToList() from the end of the query as its default is IObservable<T>.
No need to give the name of the column, simply use the already established index:
int idForeignKey = inputIdFkey //Implemented on the WebPage for testing purposes
List<int> intList = new List<int>();
List<string> stringList = new List<string>();
List<DateTime> dateList = new List<DateTime>();
string oString = "Select * from Table where ForeignKey = #fKey";
conn.Open();
SqlCommand oCmdSleep = new SqlCommand(oString, conn);
oCmdSleep.Parameters.AddWithValue("#fKey", idForeignKey);
using (SqlDataReader oReader = oCmdSleep.ExecuteReader())
{
while (oReader.Read())
{
intList.Add(oReader.GetDateTime(0));
dstringList.Add(oReader.GetDateTime(3));
dateList.Add(oReader.GetDateTime(4));
}
}
conn.Close();
Here is a breakdown:
listVariable.Add(oReader.GetDataType("Index of column"));
This way you get to retrieve all row data for shared foreign key and the option to do so for as many columns as you want.

The secure way to return some value from database (SQL SERVER & ASP.NET)

Is the code below implementing the secure way to retrieve the data from database?
help me please, I don't understand about SQL Injection. Someone told me this code can easily get injected. If yes, can somebody explain it? Thank you.
public int CheckID(string column, string table, string wheres)
{
int i = 0;
sqlcon = ConnectToMain();
string sqlquery = "SELECT "+column+" FROM "+table+" "+wheres+"";
using (sqlcon)
{
sqlcon.Open();
SqlCommand sqlcom = new SqlCommand(sqlquery, sqlcon);
using (sqlcom)
{
SqlDataReader dr = sqlcom.ExecuteReader();
dr.Read();
if (dr.HasRows)
{
i = dr.GetInt32(0);
}
else
{
i = 0;
}
}
sqlcon.Close();
}
return i;
}
This code has far too many problems.
Table, column and criteria are passed as strings and concatenated, which means that the code is prone to SQL injection.
Database details like table, column criteria are spilled into the function's caller. Are you going to use this method to query anything other than a Visitor table?
A reader is used when only a single value is wanted.
The connection is created outside the using block and stored in a field.
This is definitelly a memory leak and probably a connection leak as well. Just create the connection locally.
A simple command call fixes all of these problems:
public int CheckIDVisitor(visitorName)
{
string query = "SELECT ID FROM Visitors where Name=#name";
using (var sqlConn=new SqlConnection(Properties.Default.MyDbConnectionString))
using( var cmd=new SqlCommand(query,sqlConn))
{
var cmdParam=cmd.Parameters.Add("#name",SqlDbType.NVarChar,20);
cmdParam.Value=visitorName;
sqlConn.Open();
var result=(int?)cmd.ExecuteScalar();
return result??0;
}
}
You could also create the command in advance and store it in a field. You can attach the connection to the command each time you want to execute it:
public void InitVisitorCommand()
{
string query = "SELECT ID FROM Visitors where Name=#name";
var cmd=new SqlCommand(query,sqlConn);
var cmdParam=cmd.Parameters.Add("#name",SqlDbType.NVarChar,20);
_myVisitorCommand=cmd;
}
...
public int CheckIDVisitor(visitorName)
{
using (var sqlConn=new SqlConnection(Properties.Default.MyDbConnectionString))
{
_myVisitorCommand.Parameters.["#name"]Value=visitorName;
_myVisitorCommand.Connection=sqlConn;
sqlConn.Open();
var result=(int?)cmd.ExecuteScalar();
return result??0;
}
}
An even better option would be to use a micro-ORM like Dapper.Net to get rid of all this code:
public int CheckIDVisitor(visitorName)
{
using (var sqlConn=new SqlConnection(Properties.Default.MyDbConnectionString))
{
string sql = "SELECT ID FROM Visitors WHERE name=#name"
var result = conn.Query<int?>(sql, new { name = visitorName);
return result??0;
}
}
Or
public int[] CheckIDVisitors(string []visitors)
{
using (var sqlConn=new SqlConnection(Properties.Default.MyDbConnectionString))
{
string sql = "SELECT ID FROM Visitors WHERE name IN #names"
var results = conn.Query<int?>(sql, new { names = visitors);
return results.ToArray();
}
}

C# and SQLite: Resource to Array

I'm querying a database with SQLite. I'm trying to get data from this database, save it in an array, then return to the controller. I need to present this data using a foreach loop in my view.
string sql = "select * from Tasks Where UserId = " + userId.ToString();
using (SQLiteConnection conn = new SQLiteConnection(connString))
{
SQLiteCommand cmd = new SQLiteCommand(sql, conn);
conn.Open();
using (SQLiteDataReader rdr = cmd.ExecuteReader())
{
int i = 0;
while (rdr.Read())
{
//here is what i would do in PHP
$array[$i]['name'] = $rdr[i]["name"];
$array[$i]['key'] $rdr[$i]["key"];
}
}
}
return array;
Firstly, learn to use parameterised queries not string concatenation as this will help prevent SQL injection attacks.
string sql = "select * from Tasks Where UserId = #userId";
Also, if you create a class to represent a record in your Tasks table then you can build instances of this object and return them in a list which will make using the code easier since instead of having untyped arrays, you will have an object with properties (in your view you can do foreach (var task in Model) where Model is a List<Task>.
public class Task
{
public int Id { get; set; }
public string Name { get; set; }
public string Key { get; set; }
}
var tasks = new List<Task>(); // create a list to populate with tasks
using (var connection = new SQLiteConnection(connString))
{
var command = new SQLiteCommand(sql, conn);
command.Parameters.Add("#userId", userId); // only do .ToString on userId if the column is a string.
connection.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var task = new Task();
task.Id = (int)reader["id"]; // the name of the column in the reader will match the column in the Tasks table.
task.Name = (string)reader["name"];
task.Key = (string)reader["key"];
tasks.Add(task);
}
}
}
return tasks;
Instead of writing all the query logic and creating objects, you can use frameworks called Object Relational Mappers (ORM) to do this for you. There are a number of them around, some more simple than others. A MicroORM may suit your purposes, they are simple and easy to use (I have built one called MicroLite but there are others such as dapper or PetaPoco. If you want something more powerful, NHibernate and Entity Framework are popular choices.

Filling custom C# objects from data received stored procedure

public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Address
{
public string City { get; set; }
public string Country { get; set; }
}
/*
* There are 2 c# objects i have shown
* There is a stored procedure in my application which
* returns data for both objects simultaneously
* eg
* select FirstName, LasteName from Users where something="xyz"
* select City,Country from Locations where something="xyz"
*
* both queries are run by single procedure
* Now how can i fill both objects with from that stored procedure in asp.net using c#
*/
Use ADO.NET, open a SqlDataReader on a SqlCommand object executing the SP with the parameters. Use the SqlDataReader.NextResult method to get the second result set.
Basically:
SqlConnection cn = new SqlConnection("<ConnectionString>");
cn.Open();
SqlCommand Cmd = new SqlCommand("<StoredProcedureName>", cn);
Cmd.CommandType = System.Data.CommandType.StoredProcedure;
SqlDataReader dr = Cmd.ExecuteReader(CommandBehavior.CloseConnection);
while ( dr.Read() ) {
// populate your first object
}
dr.NextResult();
while ( dr.Read() ) {
// populate your second object
}
dr.Close();
You could use ADO.net and design a dataset which will create the classes for you so your queries will execute and read into classes which store the data you got.
http://msdn.microsoft.com/en-us/library/aa581776.aspx
That is an excellent tutorial on how to create a data access layer, which is what it sounds like you want to do.
using(SqlConnection connexion = new Sqlconnection(youconenctionstring))
using(SqlCommand command = conenxion.Createcommand())
{
command.Commandtext = "yourProcName";
command.CommandType = CommandType.StoredProcedure;
command.Paramters.Add("#yourparam",yourparamvalue);
connexion.Open();
SqlDataReader reader = command.ExecuteReader();
List<User> users = new List<User>;
List<Adress> adresses = new List<User>;
while(read.Read())
{
User user = new User();
user.firstName = (string) read["FirstName"];
users.Add(user);
}
read.NextResult();
while(read.Read)
{
Address address = new Address();
address.City = (string) read["Name"];
adresses.Add(address);
}
//make what you want with your both list
}
Linq to SQL, Entity Framework, or NHibernate would be my suggestions.
Check out the Enterprise library, specifically the Data Access block from microsoft patterns and practices. Even if you don't use it, you can steal, er... borrow code from it to do what you want.
http://www.codeplex.com/entlib

Categories

Resources