I want to write a small application in Winforms, where I will be able to write some words and write them to a SQL database using ADO.net.
I'm having trouble when I want to write a string with a placeholder like:
Give me your '%s' right now!
What is recorded in my DB is:
Give me your **"%s"** right now!
How can I overcome this be changing the string via C# that is transferred to my DB?
This is part of my code:
public virtual int Split(global::System.Nullable<int> ID, object SplitXMLDoc, string CreatedBy)
{
global::System.Data.SqlClient.SqlCommand command = this.CommandCollection[4];
if ((ID.HasValue == true)) {
command.Parameters[1].Value = ((int)(ID.Value));
}
else {
command.Parameters[1].Value = global::System.DBNull.Value;
}
if ((SplitXMLDoc == null)) {
command.Parameters[2].Value = global::System.DBNull.Value;
}
else {
command.Parameters[2].Value = ((object)(SplitXMLDoc));
}
if ((CreatedBy == null)) {
command.Parameters[3].Value = global::System.DBNull.Value;
}
else {
command.Parameters[3].Value = ((string)(CreatedBy));
}
global::System.Data.ConnectionState previousConnectionState = command.Connection.State;
if (((command.Connection.State & global::System.Data.ConnectionState.Open)
!= global::System.Data.ConnectionState.Open)) {
command.Connection.Open();
}
int returnValue;
try {
returnValue = command.ExecuteNonQuery();
}
finally {
if ((previousConnectionState == global::System.Data.ConnectionState.Closed))
{
command.Connection.Close();
}
}
return returnValue;
}
You use parameterized sql.
string val = "'%s'".Replace("'","\"");
string sql = "INSERT Into Table1 (value) values (#Value)";
SqlCommand cmd = new SqlCommand(sql, connection);
cmd.Parameters.AddWithValue("#Value",val);
cmd.ExecuteNonQuery();
Related
I'm having trouble with a SQL Server connection in C#.
My program is simple, input a name and a description, then save it with Active Record in a database. But the data is not begin saved.
When I consult the SQL Server database (Select top 1000 rows), nothing is showing.
What part of the code is not working, the C# or the SQL? I'm using a console command for the inputs.
My class Neighborhood:
private string name;
private string description;
public string Name { get { return name; } set { name = value; } }
public string Description { get { return description; } set { description = value; } }
public Neighborhood(string name, string description)
{
this.Name = name;
this.Description = description;
}
public Neighborhood(){}
public bool Save()
{
bool retor = false;
string strCon = "Data Source=FACUNDO\\USARESTESQLSERVE; Initial Catalog = TestDB; Integrated Security = SSPI; ";
SqlConnection con = new SqlConnection(strCon);
string insert = "INSERT INTO Neighborhood (Name, Description) VALUES (#nom, #desc);";
SqlCommand command = new SqlCommand(insert, con);
command.Parameters.AddWithValue("#nam", this.Name);
command.Parameters.AddWithValue("#desc", this.Description);
try
{
con.Open();
retor = true;
}
catch
{
retor = false;
throw;
}
finally
{
if (con.State == ConnectionState.Open)
con.Close();
}
return retor;
}
And this is the SQL code
CREATE DATABASE TestDB
USE TestDB
CREATE TABLE Neighborhood
(
Name VARCHAR(30) NOT NULL,
Description VARCHAR(50) NOT NULL,
CONSTRAINT PK_Neighborhood PRIMARY KEY (Name)
)
You have a typo here, the correct is #nom:
command.Parameters.AddWithValue("#nom", this.Name);
You just forgot to execute the query with command.ExecuteNonQuery();:
try
{
con.Open();
// execute the query command
command.ExecuteNonQuery();
retor = true;
}
catch
{
retor = false;
throw;
}
finally
{
if (con.State == ConnectionState.Open)
con.Close();
}
return retor;
I am attempting to create a database access layer. I am looking for some improvements to this class/recommendations on best practice. It would be helpful if someone could point me to documentation on how this could be potentially done/things to consider. I have looked at using entity framework but it does not seem applicable, however, should I really be looking to move to EF? Is ADO.NET an outdated way of doing this?
public static IDbCommand GetCommandObject(string Connstring)
{
IDbConnection conn = new SqlConnection(Connstring);
return new SqlCommand { Connection = (SqlConnection)conn };
}
public static void AddParameter(ref IDbCommand cmd, string Name, object value, DbType ParamType)
{
IDbDataParameter Param = cmd.CreateParameter();
Param.DbType = ParamType;
Param.ParameterName = (Name.StartsWith("#")) ? "" : "#"; //# character for MS SQL database
Param.Value = value;
cmd.Parameters.Add(Param);
}
public static Int32 ExecuteNonQuery(string SQL, IDbCommand cmd = null)
{
Boolean CommitTrans = true;
Boolean CloseConn = true;
SqlTransaction Trans = null;
try
{
//IF Required - create command object if required
if (cmd == null) { cmd = DB.GetCommandObject(""); }
//Add the commandtext
cmd.CommandText = SQL;
if (cmd.Connection == null) { throw new Exception("No connection set"); }
//IF REQUIRED - open the connection
if (cmd.Connection.State == ConnectionState.Closed)
{
cmd.Connection.Open();
}
else
{
CloseConn = false;
}
if (cmd.Transaction != null)
{
//We have already been passed a Transaction so dont close it
CommitTrans = false;
}
else
{
//Create and open a new transaction
Trans = (SqlTransaction)cmd.Connection.BeginTransaction();
cmd.Transaction = Trans;
}
Int32 rtn = cmd.ExecuteNonQuery();
if (CommitTrans == true) { Trans.Commit(); }
return rtn;
}
catch (Exception e)
{
if (CommitTrans == true) { Trans.Rollback(); }
throw new Exception();
}
finally
{
if (CloseConn == true)
{
cmd.Connection.Close();
cmd = null;
}
}
}
public static object ExecuteScalar(string SQL, IDbCommand cmd, Boolean NeedsTransaction = true)
{
Boolean CommitTrans = true;
Boolean CloseConn = true;
SqlTransaction Trans = null;
try
{
//IF Required - create command object if required
if (cmd == null) { cmd = DB.GetCommandObject(""); }
//Add the commandtext
cmd.CommandText = SQL;
//IF REQUIRED - create default Connection to CourseBuilder DB
if (cmd.Connection == null) { throw new Exception("No Connection Object"); }
//IF REQUIRED - open the connection
if (cmd.Connection.State == ConnectionState.Closed)
{
cmd.Connection.Open();
}
else
{
CloseConn = false;
}
if (NeedsTransaction == true)
{
if (cmd.Transaction != null)
{
//We have already been passed a Transaction so dont close it
CommitTrans = false;
}
else
{
//Create and open a new transaction
Trans = (SqlTransaction)cmd.Connection.BeginTransaction();
cmd.Transaction = Trans;
}
}
Object rtn = cmd.ExecuteScalar();
if (NeedsTransaction == true && CommitTrans == true) { Trans.Commit(); }
return rtn;
}
catch
{
if (NeedsTransaction == true && Trans != null) { Trans.Rollback(); }
throw new Exception();
}
finally
{
if (CloseConn == true) { cmd.Connection.Close(); cmd = null; }
}
}
public static DataRow GetDataRow(string SQL, IDbCommand cmd = null, Boolean ErrorOnEmpty = true)
{
var dt = FillDatatable(SQL, ref cmd);
if (dt.Rows.Count > 0)
{
return dt.Rows[0];
}
else
{
if (ErrorOnEmpty == true) { throw new Exception(nameof(GetDataRow) + " returned no rows."); }
return null;
}
}
public static DataTable FillDatatable(string SQL, ref IDbCommand cmd)
{
string newline = System.Environment.NewLine;
var DT = new DataTable();
Boolean LeaveConOpen = false;
try
{
//Add the commandtext
cmd.CommandText = SQL;
//IF REQUIRED - create default Connection to CourseBuilder DB
if (cmd?.Connection == null) { throw new Exception("No Connection Object"); }
if (cmd.Connection.State != ConnectionState.Open)
{
cmd.Connection.Open();
LeaveConOpen = false;
}
else
{
LeaveConOpen = true;
}
var DA = new SqlDataAdapter((SqlCommand)cmd);
DA.Fill(DT);
}
catch (Exception ex)
{
var sbErr = new StringBuilder();
sbErr.AppendLine("Parameters (type defaults to varchar(max)):" + newline);
foreach (SqlParameter p in cmd.Parameters)
{
string s = "";
sbErr.AppendLine("declare " + p.ParameterName + " varchar(max) = '" + (p.Value == DBNull.Value ? "Null" : p.Value + "'; ") + newline);
}
sbErr.AppendLine(newline + SQL + newline);
throw new Exception("Failed to FillDataTable:" + newline + newline + sbErr.ToString(), ex);
}
finally
{
if (LeaveConOpen == false) { cmd.Connection.Close(); }
}
return DT;
}
public static T CheckNull<T>(T value, T DefaultValue)
{
if (value == null || value is System.DBNull)
{
return DefaultValue;
}
else
{
return value;
}
}
Couple of things to keep in mind when you are creating a DAL
DAL should be able to cater to multiple Databases (oracle , sql , mysql etc..)
You should have minimum of DB , Connection , Command and Reader implementations of each.
Do not worry about the connection pool
Be aware of the transaction scope , Especially when you are trying to save nested objects. (For Eg: by saving company, you are saving Company and Company.Employees and Employee.Phones in a single transaction)
Alternative is to use something like Dapper.
enter image description here
I have a stored procedure that returns a single record, either null or data if present.
In my code I need to check what that procedure returns. What is the right way to do it?
Now when, running the code I have an exception saying: "Invalid attempt to read when no data is present." I'm using Visual Studio 2005.
Here is my method:
public static String GetRegionBasedOnIso(String isoNum)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString);
String region = null;
try
{
using (SqlCommand cmd = new SqlCommand("MyProc", conn))
{
conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#isoNum", isoNum);
using (SqlDataReader dr = cmd.ExecuteReader())
{
if (dr.IsDBNull(0))
{
return null;
}
else
{
region = (String)dr["region"];
}
}
}
}
catch (Exception e)
{
throw new System.Exception(e.Message.ToString());
}
finally
{
conn.Close();
}
return region;
}
What can I do to fix it? Thank you
if (dr.Read())
{
if (dr.IsDBNull(0))
{
return null;
}
else
{
region = (String)dr["region"];
}
}
else
{
// do something else as the result set is empty
}
I want to make a library system in C#. In this system when a book is issued it should automatically reduce the book quantity in database. When book quantity == 0 there should be a message box showing "not available".
This is my code:
private void btnIssue_Click(object sender, EventArgs e)
{
if (cmbResID.Text != "" && cmbMemID.Text != "" && cmbBookID.Text != "" && txtBkTitle.Text != "" && txtCategory.Text != "" && txtAuthor.Text != "" && txtIssueDate.Text != "" && txtActDate.Text != "")
{
SqlCommand Quantity = new SqlCommand("Select * from tblBookDetails where Book_ID = '" + cmbBookID.Text +"'");
DataSet ds = Library.Select(Quantity);
if (ds.Tables[0].Rows.Count > 0)
{
textBox1.Text = ds.Tables[0].Rows[0].ItemArray.GetValue(5).ToString();
int b = Convert.ToInt32(textBox1.Text);
if (b > 0)
{
//a = a - 1;
//int b = Convert.ToInt32(a);
//label15.Text = a.ToString();
SqlCommand update=new SqlCommand("UPDATE tblBookDetails SET Quantity=Quantity-1 WHERE Book_ID='"+ cmbBookID +"'");
Library.ExecuteInsert(update);
SqlCommand save = new SqlCommand("insert into tblBookIssue values(#ResID,#Member_ID,#Book_ID,#Issue_Date,#Act_Ret_Date)");
save.Parameters.AddWithValue("#ResID", cmbResID.Text);
save.Parameters.AddWithValue("#Member_ID", cmbMemID.Text);
save.Parameters.AddWithValue("#Book_ID", cmbBookID.Text);
save.Parameters.AddWithValue("#Issue_Date", txtIssueDate.Text);
save.Parameters.AddWithValue("#Act_Ret_Date", txtActDate.Text);
Library.Insert(save);
MessageBox.Show("Book Issued", "Book Issue", MessageBoxButtons.OK, MessageBoxIcon.Information);
clear();
}
else
{
MessageBox.Show("this book is not available");
}
}
}
else
{
MessageBox.Show("FILL COLUMS");
}
}
Executing SQL based off of text boxes is very unsafe and Prone to SQL injection attacks. Also, to follow Object Oriented program and make much cleaner code it would be advisable to make a Book object, I completed some code below which shows an example including the book incrementer. It would be better to make focused stored procs which execute gets for books and updates for book checkouts. You will have to turn your basic select into a stored proc, and write another proc which looks at the quantity and if quantity < 1 return 0 else return 1. Let me know if you need more info, this code should help you get rolling
using System;
using System.Data;
using System.Data.SqlClient;
namespace MockLibrary
{
internal class Book
{
#region Constructors
public Book()
{
}
public Book(string resId, string memberId, string bookId, DateTime issueDate, DateTime actRetDate)
{
this.ResId = resId;
this.MemberId = memberId;
this.BookId = bookId;
this.IssueDate = issueDate;
this.ActRetDate = actRetDate;
}
#endregion
#region Properties
private string _ResID;
private string _MemberID;
private string _BookId;
private DateTime _IssueDate;
private DateTime _ActRetDate;
public string ResId
{
get { return _ResID; }
set { _ResID = value; }
}
public string MemberId
{
get { return _MemberID; }
set { _MemberID = value; }
}
public string BookId
{
get { return _BookId; }
set { _BookId = value; }
}
public DateTime IssueDate
{
get { return _IssueDate; }
set { _IssueDate = value; }
}
public DateTime ActRetDate
{
get { return _ActRetDate; }
set { _ActRetDate = value; }
}
#endregion
public Book GetBookByID(string resId, string memberId)
{
try
{
using (SqlConnection con = new SqlConnection("put your db con string here"))
{
using (SqlCommand cmd = new SqlCommand("sp_GetBookById", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ResId", SqlDbType.VarChar).Value = resId;
cmd.Parameters.Add("#MemberId", SqlDbType.VarChar).Value = memberId;
con.Open();
cmd.ExecuteNonQuery();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Book newBook = new Book(rdr["ResId"].ToString(),rdr["MemberId"].ToString(),rdr["BookId"].ToString(),DateTime.Now,DateTime.Now);
return newBook;
}
}
}
}
catch
{
throw new Exception("something went wrong");
}
return null;
}
public bool CheckoutBook(string resId, string memberId)
{
using (SqlConnection con = new SqlConnection("put your db con string here"))
{
using (SqlCommand cmd = new SqlCommand("sp_CheckoutBook", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ResId", SqlDbType.VarChar).Value = resId;
cmd.Parameters.Add("#MemberId", SqlDbType.VarChar).Value = memberId;
con.Open();
cmd.ExecuteNonQuery();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
if (rdr["checkoutsuccessful"].ToString() == "1")
{
return true;
}
}
}
}
return false;
}
}
}
when user returns a book:-
MySqlCommand cm1;
cm1 = new MySqlCommand("update addbook set bookquantity=bookquantity+1 where bookname='" + txt_bookname.Text + "'",con);
cm1.ExecuteNonQuery();
I have a ugly code that can't be reused. I have many similar queries. I want to rewrite it with SqlParameterCollectionExtensions or other better ways. But I don't know about SqlParameterCollectionExtensions at all.
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
SqlConnection con = new SqlConnection(strCon);
con.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "UPDATE Problem_DE SET ProbDesc = #ProbDesc, field_1 = #field_1, field_2 = #field_2, field_3 = #field_3, field_4 = #field_4, field_5 = #field_5, field_6 = #field_6, field_7 = #field_7 WHERE (ProbId = #ProbId)";
if (e.NewValues["ProbDesc"] == null)
cmd.Parameters.AddWithValue("#ProbDesc", DBNull.Value);
else
cmd.Parameters.AddWithValue("#ProbDesc", e.NewValues["ProbDesc"]);
if (e.NewValues["field_1"] == null)
cmd.Parameters.AddWithValue("#field_1", DBNull.Value);
else
cmd.Parameters.AddWithValue("#field_1", e.NewValues["field_1"]);
if (e.NewValues["field_2"] == null)
cmd.Parameters.AddWithValue("#field_2", DBNull.Value);
else
cmd.Parameters.AddWithValue("#field_2", e.NewValues["field_2"]);
if (e.NewValues["field_3"] == null)
cmd.Parameters.AddWithValue("#field_3", DBNull.Value);
else
cmd.Parameters.AddWithValue("#field_3", e.NewValues["field_3"]);
if (e.NewValues["field_4"] == null)
cmd.Parameters.AddWithValue("#field_4", DBNull.Value);
else
cmd.Parameters.AddWithValue("#field_4", e.NewValues["field_4"]);
\\ blah blah
cmd.ExecuteNonQuery();
con.Close();
}
The sql parameters come from e or textbox etc.
Thanks.
Maybe something like this? I assume the problem is that you have a variable number of values, depending on the problem table?
private void UpdateProblem(string problemName, string problemDescription, int problemId, object[] fieldValues)
{
SqlConnection con = null;
SqlCommand cmd = new SqlCommand();
StringBuilder sql = new StringBuilder();
int fieldCounter = 1;
// start building the sql statement
sql.AppendFormat("UPDATE {0} SET ProbDesc = #ProbDesc", problemName);
// add the 'description' parameter
cmd.Parameters.Add(new SqlParameter("#ProbDesc", problemDescription));
// add each field value to the update statement... the SqlParameter will infer the database type.
foreach(object fieldValue in fieldValues)
{
// add additional SET clauses to the statement
sql.AppendFormat(",field{0} = #field{0}", fieldCounter);
// add the field parameter to the command's collection
cmd.Parameters.Add(new SqlParameter(String.Format("#field{0}", fieldCounter), fieldValue));
fieldCounter++;
}
// finish up the SQL statement by adding the where clause
sql.Append(" WHERE (ProbId = #ProbId)");
// add the 'problem ID' parameter to the command's collection
cmd.Parameters.Add(new SqlParameter("#ProbId", problemId));
// finally, execute the SQL
try
{
con.Open();
cmd.Connection = con;
cmd.CommandText = sql.ToString();
cmd.ExecuteNonQuery();
}
catch(SqlException ex)
{
// do some exception handling
}
finally
{
if(con != null)
con.Dispose();
}
}
An example to call this code would be:
public void UpdateProblemDe()
{
int problemId = FetchCurrentProblemId();
string field1 = e.NewValues["field_1"];
string field2 = e.NewValues["field_2"];
string field3 = ddlField3.SelectedValue;
int field4 = Convert.ToInt32(e.NewValues["field_4"]);
string field5 = txtField5.Text;
DateTime field6 = DateTime.Now.AddSeconds(Convert.ToInt32(ddlField6.SelectedValue));
string field7 = txtField7.Text;
object[6] fieldValues;
if(field1 != null)
fieldValues[0] = field1;
else
fieldValues[0] = DBNull.Value;
if(field2 != null)
fieldValues[1] = field2;
else
fieldValues[1] = DBNull.Value
fieldValues[2] = field3;
fieldValues[3] = field4;
fieldValues[4] = field5;
fieldValues[5] = field6;
fieldValues[6] = field7;
UpdateProblem("Problem_DE", "Houston, we have a problem", problemId, fieldValues);
}
The example code above is obviously just a demonstration of how to make an array of objects stored from page control values and doesn't include any data validation that you will need to implement in production code.
If you won't know how big the object[] array needs to be at runtime, you can change it to be a generic List of objects and add the items dynamically.
Based on this answer
Create new SQLCommand's or reuse the same one
you could refactor your code the following way
public class DbHepler
{
private readonly string _connectionString;
public DbHepler(string connectionString)
{
_connectionString = connectionString;
}
public void ExecuteNonQuery(string query)
{
ExecuteNonQuery(query, null);
}
public void ExecuteNonQuery(string query, Dictionary<string, object> parameters)
{
using (SqlConnection conn = new SqlConnection(_connectionString))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = query;
if (parameters != null)
{
foreach (string parameter in parameters.Keys)
{
cmd.Parameters.AddWithValue(parameter, parameters[parameter] ?? DBNull.Value);
}
}
cmd.ExecuteNonQuery();
}
conn.Close();
}
}
}
your code will look something like:
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
string query = "UPDATE Problem_DE SET ProbDesc = #ProbDesc, field_1 = #field_1, field_2 = #field_2, field_3 = #field_3, field_4 = #field_4, field_5 = #field_5, field_6 = #field_6, field_7 = #field_7 WHERE (ProbId = #ProbId)";
Dictionary<string, object> parameters = new Dictionary<string, object>();
if (e.NewValues["ProbDesc"] == null)
parameters.Add("#ProbDesc", null);
else
parameters.Add("#ProbDesc", e.NewValues["ProbDesc"]);
//blah blah
DbHepler dbHepler = new DbHepler("your sql connection info");
dbHepler.ExecuteNonQuery(query, parameters);
}