Cannot save data using C# code and Multitier architecture - c#

This code always ends up returning false:
tblDars tblDrs = new tblDars();
tblDrs.ID = Convert.ToInt32(txt_subjectID.Text);
tblDrs.Name = txt_subject.Text;
tblDrs.Vahed = Convert.ToInt32(txt_units.Text);
if (!Data.insertSubject(tblDrs))
{
// Cannot save data
}
I am using pre-written stored procedures to save data. I have a class called Database:
public class Database
{
SqlConnection sc = new SqlConnection(WebConfigurationManager.ConnectionStrings["School"].ConnectionString);
public Database()
{ }
//begin insertSubject
public bool insertSubject(tblDars tbldrs)
{
sc.Open();
try
{
SqlCommand command = new SqlCommand();
command.CommandType = CommandType.StoredProcedure;
command.Connection = sc;
command.CommandText = "InsertDars";
SqlParameter param1 = new SqlParameter("#id", tbldrs.ID);
SqlParameter param2 = new SqlParameter("#Name", tbldrs.Name);
SqlParameter param3 = new SqlParameter("#Vahed", tbldrs.Vahed);
command.ExecuteNonQuery();
}
catch (Exception ex)
{
sc.Close();
return false;
}
finally
{
if (sc.State != ConnectionState.Closed)
{
sc.Close();
}
}
return true;
}
//end insertSubject
}
Also, the code for the tblDars class is as follows:
public class tblDars
{
public tblDars()
{
//
// TODO: Add constructor logic here
//
}
private int id;
private string name;
private int vahed;
public int ID
{
set { id = value; }
get { return id; }
}
public string Name
{
set { name = value; }
get { return name; }
}
public int Vahed
{
set { vahed = value; }
get { return vahed; }
}
}
Already, I tried to save another form (with more fields)'s data using the same procedure. It was a failure. Where is the problem?

You are never adding the parameters to your SQLCommand. Assuming your parameters are valid your code should look something like this:
try
{
SqlCommand command = new SqlCommand();
command.CommandType = CommandType.StoredProcedure;
command.Connection = sc;
command.CommandText = "InsertDars";
SqlParameter param1 = new SqlParameter("#id", tbldrs.ID);
SqlParameter param2 = new SqlParameter("#Name", tbldrs.Name);
SqlParameter param3 = new SqlParameter("#Vahed", tbldrs.Vahed);
/*NEW*/
command.Parameters.Add(param1);
command.Parameters.Add(param2);
command.Parameters.Add(param3);
command.ExecuteNonQuery();
}
alternatively you could write it like this:
try
{
SqlCommand command = new SqlCommand();
command.CommandType = CommandType.StoredProcedure;
command.Connection = sc;
command.CommandText = "InsertDars";
//watch for appropriate SqlDbType
//reference: http://msdn.microsoft.com/de-de/library/system.data.sqldbtype(v=vs.110).aspx
command.Parameters.Add("#id", SqlDbType.Int).Value = tbldrs.ID;
command.Parameters.Add("#Name", SqlDbType.VarChar).Value = tbldrs.Name;
command.Parameters.Add("#Vahed", SqlDbType.VarChar).Value = tbldrs.Vahed;
command.ExecuteNonQuery();
}

Related

C# Web API Parameter Always Returns All Values Instead of One

I am working on a Web API in C# and am getting my data from a SQL Database. The Get method returns all rows of (student) data, however even when I put a single student number in the GET call, it still returns all rows of data instead of a single row for the specified student. In my Roles Class I have;
public class Roles
{
List<Roles> studentRoles = new List<Roles>();
public string UserName { get; set; }
public string PersonName { get; set; }
public string Profile { get; set; }
public string Level { get; set; }
public int Year { get; set; }
public string Department { get; set; }
}
public class readRoles : Roles
{
public readRoles(DataRow dataRow)
{
UserName = (string)dataRow["UserName"];
PersonName = (string)dataRow["PersonName"];
Profile = (string)dataRow["Profile"];
Level = (string)dataRow["Level"];
Year = Convert.ToInt32(dataRow["Year"]);
Department = (dataRow["Department"] == DBNull.Value) ? "No Department" : dataRow["Department"].ToString();
}
public string UserName { get; set; }
public string PersonName { get; set; }
public string Profile { get; set; }
public string Level { get; set; }
public int Year { get; set; }
public string Department { get; set; }
}
In my Controller I have this;
List<Roles> studentRoles = new List<Roles>();
private SqlDataAdapter _adapter;
public IEnumerable<Roles> Get()
{
//Create link to database
string connString;
SqlConnection con;
connString = #"XXX";
DataTable _dt = new DataTable();
con = new SqlConnection(connString);
con.Open();
var sql = "some sql here";
SqlCommand CMD = new SqlCommand();
CMD.Connection = con;
CMD.CommandText = sql;
CMD.CommandType = System.Data.CommandType.Text;
SqlDataReader dr = CMD.ExecuteReader();
_adapter = new SqlDataAdapter
{
SelectCommand = new SqlCommand(sql, con)
};
_adapter.Fill(_dt);
List<Roles> roles = new List<Roles>(_dt.Rows.Count);
if (_dt.Rows.Count > 0)
{
foreach (DataRow studentrole in _dt.Rows)
{
roles.Add(new readRoles(studentrole));
}
}
return roles;
}
The above returns all the data as it should. To return a single row of data, I have the below Method but it still returns every single row instead of the row for the specified one when I do e.g. https://localhost:XXXXX/custom-roles-api/campusCustomRoles/12345;
[HttpGet]
public IHttpActionResult Get(string userName)
{
string connString;
SqlConnection con;
connString = #"XXX";
DataTable _dt = new DataTable();
con = new SqlConnection(connString);
con.Open();
var sql = "select distinct .... where student_reference = " + userName +;
SqlCommand CMD = new SqlCommand();
CMD.Connection = con;
CMD.CommandText = sql;
CMD.CommandType = System.Data.CommandType.Text;
SqlDataReader dr = CMD.ExecuteReader();
_adapter = new SqlDataAdapter
{
SelectCommand = new SqlCommand(sql, con)
};
_adapter.Fill(_dt);
List<Roles> roles = new List<Roles>(_dt.Rows.Count);
if (_dt.Rows.Count > 0)
{
foreach (DataRow studentrole in _dt.Rows)
{
roles.Add(new readRoles(studentrole));
}
}
var singlestu = roles.FirstOrDefault(e => e.UserName == userName);
return Ok(singlestu)
;
}
In the above example, I expect only data for student 12345 to be returned, but alas, all records are retrieved. In my WebConfig file, I have a custom Route like so;
public static void Register(HttpConfiguration config)
{
// Web API routes
// This is the original Route
//config.MapHttpAttributeRoutes();
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{Controller}/{id}",
// //routeTemplate: "api/{controller}/{action}/{id}",
// defaults: new { id = RouteParameter.Optional }
//);
// Custom Route
config.MapHttpAttributeRoutes();
// Define route
System.Web.Http.Routing.IHttpRoute rolesRoute = config.Routes.CreateRoute("custom-roles-api/{controller}/{id}",
new { id = RouteParameter.Optional }, null);
// Add route
config.Routes.Add("DefaultApi", rolesRoute);
}
Not sure where I have gone wrong and would be grateful for any pointers.
Many thanks in advance.
EDIT: As requested, please see below code when I used parameters;
[HttpGet]
public IHttpActionResult Get(string userName)
{
string connString;
SqlConnection con;
connString = #"XXXX";
DataTable _dt = new DataTable();
con = new SqlConnection(connString);
con.Open();
var sql = "select distinct .... where student_reference =#UserName " +
"and department ='LAW' " +;
SqlParameter param = new SqlParameter();
param.ParameterName = "#UserName";
param.Value = UserName;
SqlCommand CMD = new SqlCommand();
CMD.Connection = con;
CMD.CommandText = sql;
CMD.CommandType = System.Data.CommandType.Text;
SqlDataReader dr = CMD.ExecuteReader();
_adapter = new SqlDataAdapter
{
SelectCommand = new SqlCommand(sql, con)
};
_adapter.Fill(_dt);
List<Roles> roles = new List<Roles>(_dt.Rows.Count);
if (_dt.Rows.Count > 0)
{
foreach (DataRow studentrole in _dt.Rows)
{
roles.Add(new readRoles(studentrole));
}
}
var singlestu = roles.FirstOrDefault(e => e.UserName == userName);
return Ok(singlestu)
;
}
After much head-cracking, I go it to work by converting the UserName to type int in the Roles class and the source query.

Insert null datetime from sql table into datagridview silverlight

I have problem with null values, I want to insert from sql table nulls ( from datetime column) into datagridview, and datagridview return error.
Communication Exception was unhandled by user code
Code:
public class Pismo
{
public int Id { get; set; }
public string PW { get; set; }
public DateTime? Data_Wysylki { get; set; }
}
public ObservableCollection<Pismo> ReadPisma(int id_pismo)
{
ObservableCollection<Pismo> result = new ObservableCollection<Pismo>();
string nwConn = System.Configuration.ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
SqlDataReader dr;
SqlConnection conn = new SqlConnection(nwConn);
try
{
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = conn;
cmd.CommandText = "INSERT";
cmd.Parameters.AddWithValue("#id", id);
conn.Open();
dr = cmd.ExecuteReader();
while (dr.Read())
{
Pismo wiersz = new Pismo();
wi.Id = dr.GetInt32(0);
wi.PW = dr.GetString(1);
wi.Data_Wysylki = dr.GetDateTime(2);
result.Add(wi);
}
dr.Close();
return result;
}
catch (SqlException e)
{
Pismo wi = new Pismo();
wi.Id = e.Message;
result.Add(wi);
return result;
}
finally
{
conn.Close();
};
}
<sdk:DataGridTextColumn Header="Data WysyƂki" Binding="{Binding Data_Wysylki, StringFormat='yyyy/MM/dd'}"/>
I try to add this below
if (wi.Data_Wysylki.HasValue) wi.Data_Wysylki = dr.GetDateTime(16);
after that error didnt show but in datagridview all column (even with some dates) was null

How Can I create executeReader class

Sir,
I have a connection class for ExecuteNonquery
public class Connection
{
SqlConnection conn;
SqlCommand cmd;
public void connclose()
{
conn.Close();
}
public Connection()
{
conn = new SqlConnection(#"server=ADMIN-PC;database=sample;Integrated security=true");
cmd = null;
}
public void nonquery(SqlCommand cmd)
{
conn.Open();
cmd.Connection = conn;
cmd.ExecuteNonQuery();
conn.Close();
}
In this same way I have to create a Executereader class also....What changes i should apply for that
I have a class too
public void insert(string sid, string cid, string state)
{
SqlCommand cmd = new SqlCommand("InsertState");
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#StateId", SqlDbType.VarChar).Value = sid;
cmd.Parameters.Add("#CountryId", SqlDbType.VarChar).Value = cid;
cmd.Parameters.Add("#State", SqlDbType.VarChar).Value = state;
conn.nonquery(cmd);
}
You may add this method
public SqlDataReader ReadMe(SqlCommand cmd)
{
conn.Open();
cmd.Connection = conn;
SqlDataReader reader = cmd.ExecuteReader();
return reader;
}
You can call it like this :
SqlCommand cmd = new SqlCommand("reading");
cmd.CommandType = CommandType.StoredProcedure;
using(SqlDataReader ourreader = conn.ReadMe(cmd))
{
while (ourreader.Read())
{
//some code
}
}
conn.Close();

combine two methods returning two different values

Hi I have got two methods are returning two different return type of values like int and string and I am executing query inside the method with passing different variables like the below
METHOD 1
private string SelectTransactionHistory(int transactionId, ContextObject contextObject)
{
SqlConnection con;
SqlCommand cmd;
con = new SqlConnection(contextObject.ConnectionString);
con.Open();
string returnvalue = string.Empty;
string selecteQuery = "SELECT Comments
From dbo.TransactionHistory
WHERE TransactionID = '" + transactionId + "'";
cmd = new SqlCommand(selecteQuery, con);
returnvalue = (string)cmd.ExecuteScalar();
con.Close();
return returnvalue;
}
METHOD 2
private int SelectTransactionHistoryID(string comment, ContextObject contextObject)
{
SqlConnection con;
SqlCommand cmd;
con = new SqlConnection(contextObject.ConnectionString);
con.Open();
string query = "SELECT TransactionID
From dbo.TransactionHistory
WHERE Comments = '" + comment + "'";
cmd = new SqlCommand(query, con);
int returnvalue = (int)cmd.ExecuteScalar();
con.Close();
return returnvalue;
}
I am calling these methods in another method like this
int transactionId = SelectTransactionHistoryID(comment, GetContext());
string commentsreturnValue = SelectTransactionHistory(transactionId, GetContext());
how can i combine these two methods to make more generic type..
Would any one have any suggestions on how to do this..
Many Thanks.....
You could create a method to execute any query using ado.net, for sample:
private static T ExecuteQuery<T>(ContextObject contextObject, string query)
{
T result;
using (SqlConnection con = con = new SqlConnection(contextObject.ConnectionString))
{
try
{
con.Open();
using (SqlCommand cmd = cmd = new SqlCommand(query, con))
{
result = (T)cmd.ExecuteScalar();
}
}
catch
{
result = null;
}
finally
{
con.Close();
}
}
returnr result;
}
And pass a query that return a single value (in sql we use TOP 1), something like this:
var resultComment = ExecuteQuery<string>("SELECT TOP 1 Comments From dbo.TransactionHistory WHERE TransactionID = '" + transactionId + "'");
var resultTransactionId = ExecuteQuery<int>("SELECT TOP 1 TransactionID From dbo.TransactionHistory WHERE Comments = '" + comment + "'")
I have all of my infrastructure classes setup to utilize Dapper. However you can replace the dapper extension method with a regular method.
Base Service:
public interface IService
{
T Execute<T>(Func<IDbConnection, T> query);
void Execute(Action<IDbConnection> query);
}
public sealed class Service : IService
{
private readonly string _connectionString;
public Service(string connectionString)
{
_connectionString = connectionString;
}
private IDbConnection CreateConnection()
{
var connection = new SqlConnection(_connectionString);
connection.Open();
return connection;
}
public T Execute<T>(Func<IDbConnection, T> query)
{
using (var connection = CreateConnection())
{
return query(connection);
}
}
public void Execute(Action<IDbConnection> query)
{
using (var connection = CreateConnection())
{
query(connection);
}
}
}
DTO:
public class TransactionHistory
{
public int TransactionID { get; set; }
public string Comments { get; set; }
}
Service:
public interface ITransactionHistoryService
{
IEnumerable<TransactionHistory> GetByTransactionId(int transactionId);
IEnumerable<TransactionHistory> GetByComment(string comment);
}
public sealed class TransactionHistoryService : ITransactionHistoryService
{
// Note SELECT * is frowned upon. Replace with actual column names.
private const string GetByTransactionIdQuery =
"SELECT * FROM dbo.TransactionHistory WHERE TransactionID = #TransactionId";
private const string GetByCommentQuery =
"SELECT * FROM dbo.TransactionHistory WHERE Comments = #Comment";
private readonly IService _service;
public TransactionHistoryService(IService service)
{
_service = service;
}
public IEnumerable<TransactionHistory> GetByTransactionId(int transactionId)
{
var result = _service.Execute(c =>
c.Query<TransactionHistory>(GetByTransactionIdQuery,
new { TransactionId = transactionId }));
return result;
}
public IEnumerable<TransactionHistory> GetByComment(string comment)
{
var result = _service.Execute(c =>
c.Query<TransactionHistory>(GetByCommentQuery,
new { Comment = comment }));
return result;
}
}
You can create a single function as follows- (Not tested)
private string[] SelectTransactionHistory(int transactionId, ContextObject contextObject)
{
string[] returnValues;
SqlConnection con;
SqlCommand cmd;
SqlDataReader reader;
con = new SqlConnection(contextObject.ConnectionString);
con.Open();
string returnvalue = string.Empty;
string selecteQuery = "SELECT TransactionID, Comments From dbo.TransactionHistory WHERE TransactionID = '" + transactionId + "'";
cmd = new SqlCommand(selecteQuery, con);
reader = cmd.ExecuteReader();
while(reader.Read())
{
returnValues[0] = reader["TransactionID"].ToString();
returnValues[1] = reader["Comments"].ToString();
}
con.Close();
return returnValues;
}
And then call it as follows-
string[] TransactionHistory = SelectTransactionHistory(transactionId, GetContext());
int transactionId = Convert.ToInt32(TransactionHistory[0]);
string commentsreturnValue = TransactionHistory[1];
The above code is not tested. But you can get an idea.

ADO.NET how to add parameter if I use connection class in a separate file?

ADO.NET how to add parameter if I use class in a separate file?
Class:
class SQLconnect
{
public static void Sql(string Command_Text)
{
string connectionPath =
"Data Source=USER\\SQLEXPRESS;Initial Catalog=db;Integrated Security=SSPI;";
SqlConnection Connection = new SqlConnection(connectionPath);
Connection.Open();
SqlCommand Command = Connection.CreateCommand();
Command.CommandText = Command_Text;
Command.ExecuteNonQuery();
Connection.Close();
}
}
Parameter:
SQLconnect.Sql("INSERT INTO [dbo].[work] ([name],[code])VALUES(#name, #code)");
SqlParameter param = new SqlParameter();
param.ParameterName = "#name";
param.Value = nameTextBox.Text;
param.SqlDbType = SqlDbType.Text;
// Parameters.Add(param);
param = new SqlParameter();
param.ParameterName = "#code";
param.Value = codeTextBox.Text;
param.SqlDbType = SqlDbType.Text;
// Parameters.Add(param);
One option would be to update your SqlConnect.Sql() method to accept a set of parameters:
class SQLconnect
{
public static void Sql(string Command_Text, params SqlParameter[] parameters)
{
string connectionPath =
"Data Source=USER\\SQLEXPRESS;Initial Catalog=db;Integrated Security=SSPI;";
SqlConnection Connection = new SqlConnection(connectionPath);
Connection.Open();
SqlCommand Command = Connection.CreateCommand();
Command.CommandText = Command_Text;
if(parameters != null && parameters.Length > 0)
{
foreach(var p in parameters)
Command.Parameters.Add(p);
}
Command.ExecuteNonQuery();
Connection.Close();
}
}
Then your calling code would be something like this:
SqlParameter param1 = new SqlParameter();
param1.ParameterName = "#name";
param1.Value = nameTextBox.Text;
param1.SqlDbType = SqlDbType.Text;
param2 = new SqlParameter();
param2.ParameterName = "#code";
param2.Value = codeTextBox.Text;
param2.SqlDbType = SqlDbType.Text;
SQLconnect.Sql("INSERT INTO [dbo].[work] ([name],[code])VALUES(#name, #code)", param1, param2);
Here is my version hope it helps
public class SqlConnect
{
public string ConnectionString { get; private set; }
public string CommandText { get; private set; }
public SqlParameterCollection Parameters { get; private set; }
public SqlConnect(string connectionString, string commandText)
{
ConnectionString = connectionString;
CommandText = commandText;
Parameters = null;
}
public SqlConnect(string connectionString, string commandText, SqlParameterCollection parameters)
: this(connectionString, commandText)
{
Parameters = parameters;
}
public int Execute()
{
using (var connection = new SqlConnection(ConnectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
command.CommandText = CommandText;
foreach (var sqlParameter in Parameters)
{
command.Parameters.Add(sqlParameter);
}
int rowsAffected = command.ExecuteNonQuery();
connection.Close();
return rowsAffected;
}
}
}
You can create a separate class for Database connection...then create a properties for each parameter like follows
public class StudDataAccess
{
public string connectionString = "Data Source=USER\\SQLEXPRESS;Initial Catalog=db;Integrated Security=SSPI;";
public int pStudId
{
set;
get;
}
public string pStudName
{
set;
get;
}
public void NewStudent()
{
SqlConnection conn = new SqlConnection(connectionString);
conn.Open();
SqlCommand cmd = new SqlCommand("AddStudent", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#StudId", SqlDbType.Int).Value = pStudId;
cmd.Parameters.Add("#StudName", SqlDbType.VarChar, 50).Value = pStudName;
cmd.Prepare();
cmd.ExecuteNonQuery();
conn.Close();
}
}
Here we created two parameters id ,name so you can set values of it from the class where you need to insert,select data. as follows by creating object of that class
StudDataAccess objDataAccess = new StudDataAccess();
objDataAccess.pStudId =Convert.ToInt32(TextBox1.Text);
objDataAccess.pStudName = TextBox2.Text;
objDataAccess.NewStudent(); //Call addstudent store procedure with parameters

Categories