Parameterized SQL in C# .Net - c#

If I have code like so:
public T ExecuteQuery<T>(Func<IDataReader, T> getResult, string query, params IDataParameter[] parameters)
{
using (SqlConnection conn = new SqlConnection(this.DefaultConnectionString))
{
conn.Open();
// Declare the parameter in the query string
using (SqlCommand command = new SqlCommand(query, conn))
{
foreach (var parameter in parameters)
{
command.Parameters.Add(parameter);
}
command.Prepare();
using (SqlDataReader dr = command.ExecuteReader())
{
return getResult(dr);
}
}
}
}
public string GetMySpecId(string dataId)
{
return ExecuteQuery(
dr =>
{
if (dr.Read())
{
return dr[0].ToString();
}
return string.Empty;
},
#"select ""specId"" from ""MyTable"" where ""dataId"" = :dataId",
new SqlParameter("dataId", dataId));
}
}
How do I ensure that the
new SqlParameter("dataId", dataId));
piece of code is passing in a text or maybe an integer? Also how does the #"select..." actually work as I'm familiar to:
select id from mytable where dataId = #dataID;

I'm not sure that's parameterized properly. Take a look at the below modified code that will ensure the parameters are added properly and simplify the construction of the call to ExecuteQuery (in my opinion of course). This is pretty straight forward. The select statement is parameterized properly because it's using the #varname syntax:
"select \"specId\" from \"MyTable\" where \"dataId\" = #dataId"
Further, the parameters are typed properly because of the AddWithValue method:
command.Parameters.AddWithValue(parameter.Key, parameter.Value);
Finally, using the dictionary to send in the parameters keeps it pretty simple to construct the parameters from any structure, whether that be parameter values, or even an object.
public T ExecuteQuery<T>(Func<IDataReader, T> getResult, string query, Dictionary<string, object> parameters)
{
using (SqlConnection conn = new SqlConnection(this.DefaultConnectionString))
{
conn.Open();
// Declare the parameter in the query string
using (SqlCommand command = new SqlCommand(query, conn))
{
foreach (var parameter in parameters)
{
command.Parameters.AddWithValue(parameter.Key, parameter.Value);
}
command.Prepare();
using (SqlDataReader dr = command.ExecuteReader())
{
return getResult(dr);
}
}
}
}
public string GetMySpecId(string dataId)
{
return ExecuteQuery(
dr =>
{
if (dr.Read())
{
return dr[0].ToString();
}
return string.Empty;
},
"select \"specId\" from \"MyTable\" where \"dataId\" = #dataId",
new Dictionary<string, object>() { { "#dataId", dataId } });
}
P.S. - the # before the string in your example is just an escape sequence used in C#.

Related

Select SQL Server C# and Array with return [duplicate]

I have a SQL Server 2008 database and I am working on it in the backend. I am working on asp.net/C#
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
//how do I read strings here????
}
I know that the reader has values. My SQL command is to select just 1 column from a table. The column contains strings ONLY. I want to read the strings (rows) in the reader one by one. How do I do this?
using(SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
var myString = rdr.GetString(0); //The 0 stands for "the 0'th column", so the first column of the result.
// Do somthing with this rows string, for example to put them in to a list
listDeclaredElsewhere.Add(myString);
}
}
string col1Value = rdr["ColumnOneName"].ToString();
or
string col1Value = rdr[0].ToString();
These are objects, so you need to either cast them or .ToString().
Put the name of the column begin returned from the database where "ColumnName" is. If it is a string, you can use .ToString(). If it is another type, you need to convert it using System.Convert.
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
string column = rdr["ColumnName"].ToString();
int columnValue = Convert.ToInt32(rdr["ColumnName"]);
}
while(rdr.Read())
{
string col=rdr["colName"].ToString();
}
it wil work
Thought to share my helper method for those who can use it:
public static class Sql
{
public static T Read<T>(DbDataReader DataReader, string FieldName)
{
int FieldIndex;
try { FieldIndex = DataReader.GetOrdinal(FieldName); }
catch { return default(T); }
if (DataReader.IsDBNull(FieldIndex))
{
return default(T);
}
else
{
object readData = DataReader.GetValue(FieldIndex);
if (readData is T)
{
return (T)readData;
}
else
{
try
{
return (T)Convert.ChangeType(readData, typeof(T));
}
catch (InvalidCastException)
{
return default(T);
}
}
}
}
}
Usage:
cmd.CommandText = #"SELECT DISTINCT [SoftwareCode00], [MachineID]
FROM [CM_S01].[dbo].[INSTALLED_SOFTWARE_DATA]";
using (SqlDataReader data = cmd.ExecuteReader())
{
while (data.Read())
{
usedBy.Add(
Sql.Read<String>(data, "SoftwareCode00"),
Sql.Read<Int32>(data, "MachineID"));
}
}
The helper method casts to any value you like, if it can't cast or the database value is NULL, the result will be null.
For a single result:
if (reader.Read())
{
Response.Write(reader[0].ToString());
Response.Write(reader[1].ToString());
}
For multiple results:
while (reader.Read())
{
Response.Write(reader[0].ToString());
Response.Write(reader[1].ToString());
}
I know this is kind of old but if you are reading the contents of a SqlDataReader into a class, then this will be very handy. the column names of reader and class should be same
public static List<T> Fill<T>(this SqlDataReader reader) where T : new()
{
List<T> res = new List<T>();
while (reader.Read())
{
T t = new T();
for (int inc = 0; inc < reader.FieldCount; inc++)
{
Type type = t.GetType();
string name = reader.GetName(inc);
PropertyInfo prop = type.GetProperty(name);
if (prop != null)
{
if (name == prop.Name)
{
var value = reader.GetValue(inc);
if (value != DBNull.Value)
{
prop.SetValue(t, Convert.ChangeType(value, prop.PropertyType), null);
}
//prop.SetValue(t, value, null);
}
}
}
res.Add(t);
}
reader.Close();
return res;
}
I would argue against using SqlDataReader here; ADO.NET has lots of edge cases and complications, and in my experience most manually written ADO.NET code is broken in at least one way (usually subtle and contextual).
Tools exist to avoid this. For example, in the case here you want to read a column of strings. Dapper makes that completely painless:
var region = ... // some filter
var vals = connection.Query<string>(
"select Name from Table where Region=#region", // query
new { region } // parameters
).AsList();
Dapper here is dealing with all the parameterization, execution, and row processing - and a lot of other grungy details of ADO.NET. The <string> can be replaced with <SomeType> to materialize entire rows into objects.
Actually, I figured it out myself that I could do this:
while (rdr.read())
{
string str = rdr.GetValue().ToString().Trim();
}
In the simplest terms, if your query returns column_name and it holds a string:
while (rdr.Read())
{
string yourString = rdr.getString("column_name")
}
I usually read data by data reader this way. just added a small example.
string connectionString = "Data Source=DESKTOP-2EV7CF4;Initial Catalog=TestDB;User ID=sa;Password=tintin11#";
string queryString = "Select * from EMP";
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(queryString, connection))
{
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}", reader[0], reader[1]));
}
}
reader.Close();
}
}
You have to read database columnhere. You could have a look on following code snippet
string connectionString = ConfigurationManager.ConnectionStrings["NameOfYourSqlConnectionString"].ConnectionString;
using (var _connection = new SqlConnection(connectionString))
{
_connection.Open();
using (SqlCommand command = new SqlCommand("SELECT SomeColumnName FROM TableName", _connection))
{
SqlDataReader sqlDataReader = command.ExecuteReader();
if (sqlDataReader.HasRows)
{
while (sqlDataReader.Read())
{
string YourFirstDataBaseTableColumn = sqlDataReader["SomeColumn"].ToString(); // Remember Type Casting is required here it has to be according to database column data type
string YourSecondDataBaseTableColumn = sqlDataReader["SomeColumn"].ToString();
string YourThridDataBaseTableColumn = sqlDataReader["SomeColumn"].ToString();
}
}
sqlDataReader.Close();
}
_connection.Close();
I have a helper function like:
public static string GetString(object o)
{
if (o == DBNull.Value)
return "";
return o.ToString();
}
then I use it to extract the string:
tbUserName.Text = GetString(reader["UserName"]);

Passing function with parameter, as a parameter and returning a generic type

In the code below I am trying to pass a function func in to the GetData function. This would take the reader object and map it to a generic object.
I was hoping to pass GetData an object type along with a function to map data to that object type so I didn't have to repeatedly open / close / dispose the connection.
Is this possible or does anyone have any alternative suggestions?
public T GetData<T>(string cmdText,Func<T> func)
{
using (SqlConnection conn = new SqlConnection(connectionStringBuilder.ConnectionString))
{
using (SqlCommand cmd = new SqlCommand(cmdText, conn))
{
SqlDataReader reader = cmd.ExecuteReader();
//return func(reader);
// WITHIN THE FUNC FUNCTION:
// while (reader.Read())
// {
// Map function to T e.g
// T.property = reader["column"];
// Return T
// }
}
}
}
The signature that you're looking for is this:
T GetData<T>(string cmdText, Func<SqlDataReader, T> func)
Then you can go ahead and write your function as this:
public T GetData<T>(string cmdText, Func<SqlDataReader, T> func)
{
using (var conn = new SqlConnection(connectionStringBuilder.ConnectionString))
{
using (var cmd = new SqlCommand(cmdText, conn))
{
var reader = cmd.ExecuteReader();
return func(reader);
}
}
}
And you would use it like this:
var result = GetData("select * from Foo", dr =>
{
while (dr.Read())
{
return new { property = dr["column"] };
}
throw new DataException();
});
Now that's based on how you said you'd like to use it in your question.
However, you've made the use of the function a bit hard on yourself as you've split the implementation - part is in GetData and part is in the calling code.
You're better off using this signature:
IEnumerable<T> GetData<T>(string cmdText, Func<SqlDataReader, T> func)
Now you can write the method like this:
public IEnumerable<T> GetData<T>(string cmdText, Func<SqlDataReader, T> func)
{
using (var conn = new SqlConnection(connectionStringBuilder.ConnectionString))
{
using (var cmd = new SqlCommand(cmdText, conn))
{
var reader = cmd.ExecuteReader();
while (reader.Read())
{
yield return func(reader);
}
}
}
}
The advantage now is that the calling code is much simpler:
var results = GetData("select * from Foo", dr => new { property = dr["column"] });
This returns as many rows of data as your query returns.
If you know that your calling code only returns a single value, then you can drop a .Single() at the end of the method call to ensure you get one and only one result.

Implementing a query function with undeclared number of parameters?

I'm developing a server/client application in C#. In the earlier phases of development I was writing SQL codes each time and it caused spaghetti code. Now I'm trying to make it clean. My question is: How can I write a general query generator function with dynamic parameters?
private void button3_Click(object sender, EventArgs e)
{
try
{
SqlCommand cmd= new SqlCommand();
cmd.CommandText = "INSERT INTO tbl(line, name, firstvalue, secondvalue)" +
"VALUES(#line, #name, #value, #secondvalue)";
cmd.Parameters.AddWithValue("#line", comboBox4.Text);
cmd.Parameters.AddWithValue("#name", textBox2.Text);
cmd.Parameters.AddWithValue("#value", comboBox5.Text);
cmd.Parameters.AddWithValue("#secondvalue", comboBox6.Text);
cmd.Connection = Db.Db;
cmd.CommandType = CommandType.Text;
SqlDataReader dr = cmd.ExecuteReader();
MessageBox.Show("Saved");
}
catch (Exception ex)
{
MessageBox.Show(ex);
}
finally
{
Db.Close();
}
}
But I want to convert it into:
public void query(string commandText, params string[] parameters)
{
SqlCommand command = new SqlCommand();
command.CommandText = commandText;
foreach (var parameter in parameters)
//In this part, there can be lots of different queries and how can assign each parameter to relevant values
//Is there any change to assign them in order.
}
Well, if you insist on implementing such a routine (usually we use ORM) you have to parse the commandText; the simplest (but not the best) implementation is regular expressions (we Match parameter name within commandText, then Zip it with its value from parameters):
using System.Linq;
using System.Text.RegularExpressions;
...
public void query(string commandText, params string[] parameters) {
using (SqlCommand command = new SqlCommand()) {
command.Connection = myConnection; //TODO: put the right connection here
command.CommandText = commandText;
var prms = Regex
.Matches(commandText, #"\b#[A-Za-z_][A-Za-z_0-9]*\b")
.Cast<Match>()
.Zip(parameters, (match, value) => new {
name = match.Value,
value
});
foreach(var prm in prms)
command.Parameters.AddWithValue(prm.name, prm.value);
// Just execute; we have nothing to read (ExecuteReader)
command.ExecuteNonQuery();
}
}
Edit: If you want / ready to specify parameters' names, not only values you can try Tuples: for c# 7.0+
public void query(string commandText, params (string, object)[] parameters) {
...
foreach (var prm in parameters)
command.Parameters.AddWithValue(prm.Item1, prm.Item2);
...
}
usage
query(sql,
("#line", comboBox4.Text),
("#name", textBox2.Text),
("#id", 123), // please, note integer value
("#money", 456.78d),
...
);
for C# 6.0-:
public void query(string commandText, params Tuple<string, object>[] parameters) {
...
foreach (var prm in parameters)
command.Parameters.AddWithValue(prm.Item1, prm.Item2);
...
}
...
query(sql,
Tuple.Create("#line", comboBox4.Text),
Tuple.Create("#name", textBox2.Text),
...
);
Create an object with database parameters and set all values in it. Use Entity framework to do the rest or read from object when assigning.
I solved it and here is the solution. We will store them in the same array. So the parameters array will be:
parameters[0] = "#line"
parameters[1] = line
parameters[2] = "#name"
parameters[3] = name
and while posting them into AddWithValue() function
for (int i = 0; i < parameters.Length;)
{
command.Parameters.AddWithValue(parameters[i++] as string,parameters[i++]);
}
and we should call the query function when needed like this,
string commandText = "INSERT INTO tbl(line, name, firstvalue, secondvalue)" +
"VALUES(#line, #name, #value, #secondvalue)";
query("#line", line, "#name", name, "#value", firstvalue, "secondvalue", secondvalue);
Function Body
public class Database
{
public string executeScaler(string commandText, bool isStoredProcedure, Dictionary<string, object> dictParams = null)
{
string result = "";
DataTable dt = new DataTable();
SqlConnection con = ConnectionStrings.GetConnection();
SqlCommand cmd = new SqlCommand(commandText, con);
if (isStoredProcedure)
cmd.CommandType = CommandType.StoredProcedure;
if (dictParams != null)
foreach (KeyValuePair<string, object> rec in dictParams)
cmd.Parameters.AddWithValue("#" + rec.Key, rec.Value);
try
{
result = Convert.ToString(cmd.ExecuteScalar());
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
con.Dispose();
}
return result;
}
}
Calling Function
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add("Email", obj.Email);
dict.Add("Password", obj.Password);
Database objDB = new Database();
objDB.executeScaler("RegisterAccount", true, dict);

Generic Method to return multiple resultsets ado.net

I have the below generic method that works very well in reading 1 resultset.I have been fiddling trying to write a generic method to return multiple resulset
Could you give me a hand or suggestion how I could turn the below one into a method that returns/handle multiple resultset.
usage:
const string spName = "GetCountry";
object[] parms = { "#CountryId", countryId };
myDto dto = spName.GetOne(ToDto, parms);
return model;
public static T GetOne<T>(this string spName,
Func<IDataReader, T> createObject,
object[] parms = null)
{
try
{
using (var connection = new SqlConnection(ConnectionString))
{
using (var command = new SqlCommand())
{
command.Connection = connection;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = spName;
command.SetParameters(parms);
connection.Open();
T t = default(T);
var reader = command.ExecuteReader();
if (reader.Read())
{
t = createObject(reader);
}
return t;
}
}
}
catch (SqlException ex)
{
etc......
}
return default(T);
}
an example would be :A customer with Addresses (SP will return a customer all the related addresses by returning 2 resultsets inside a sp.)
Many thanks for any suggestions

How to check mysql db for an entry with less code

Hi i want to know if there is a more simplified method than the one im using now to find if there is an entry or not in a mysql db.
public static bool check_db_entry(string query)
{
using (var conn = new MySqlConnection(DbMethods.constr))
{
using (var cmd = new MySqlCommand(query, conn))
{
conn.Open();
using (var rdr = cmd.ExecuteReader())
{
if (rdr.Read() == false)
{
return false;
}
else
{
return true;
}
}
}
}
}
Leaving aside for now that fact that methods that accept only sql strings are inherently unsafe, this smells wrong to me. If you're going to have public methods that accept arbitrary sql commands (remember: I said "If"), then undoubtedly you have one that returns the data directly. You should rely on that as your base. Here's an example:
private static IEnumerable<IDataRecord> GetDataImpl(string query)
{
using (var conn = new MySqlConnection(DbMethods.constr))
using (var cmd = new MySqlCommand(query, conn))
{
conn.Open();
using (var rdr = cmd.ExecuteReader())
{
yield return rdr;
}
}
}
public static bool check_db_entry(string query)
{
return GetDataImpl(query).Any();
}
Note there is a reason I listed the first method as private. As written, it can have weird side effects if you don't first copy each element in the reader before returning it to a higher abstraction level in your program. But you can get the public version easily enough:
public static IEnumerable<T> GetData<T>(string query, Func<IDataRecord,T> copy)
{
return GetDataImpl(query).Select(copy);
}
Taking aside your design issues pointed in the question's comments, if you want to check the existence an entry in the database, you should always query with COUNT(*): SELECT COUNT(*) FROM yourTable [WHERE theCondition].
If that is all you pass to your function, you can then simply with:
public static bool check_db_entry(string query)
{
using (var conn = new MySqlConnection(DbMethods.constr))
{
conn.Open();
using (var cmd = new MySqlCommand(query, conn))
{
return (int)cmd.ExecuteScalar() == 1;
}
}
}
And if you want to streamline it:
public static bool check_db_entry(string query)
{
using (var conn = new MySqlConnection(DbMethods.constr))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = query;
return (int)cmd.ExecuteScalar() == 1;
}
}

Categories

Resources