SqlDataReader to populate struct - c#

There is a private "Employee" class object that mirrors the public struct "empStruct". I need to read in the rows values from the query using SQLReader to populate the struct and then set the object equal to the struct values. I think there is a simpler way but I am very new to this.
public struct empStruct
{
public int eid;
public string lastname;
public string firstname;
public DateTime birthdate;
public DateTime hiredate;
public bool ishourly;
public decimal payrate;
}
public static bool SelectEmployee(int eid)
{
empStruct SelectRecord = new empStruct();
Employee newEmp = new Employee();
string sqlText;
sqlText = "SELECT EID,EID, LastName, FirstName, BirthDate, HireDate, IsHourly, PayRate ";
sqlText += "FROM Employee ";
sqlText += "WHERE EID = #EID ";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(sqlText, connection);
command.CommandType = CommandType.Text;
command.Parameters.AddWithValue("#EID", eid);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
//Call Read before accessing data.
while (reader.Read())
{
???
}
newEmp = SelectRecord;
}
I understand that everything after "//Call Read..." is incomplete, I can't figure out exactly how this reader thing works.

while (reader.Read())
{
newEmp.eid = (int)reader("EID");
newEmp.firstname = (string)reader("FirstName");
....
}

load up the struct like this perhaps
while (reader.Read()) {
newEmp.lastname = reader.GetString(1);
newEmp.firstname = reader.GetString(2);
}

Related

How to get many field on the Query of webservice

I am making a web service get data from sql server. I need to get many fields from the sql server, but I can only get one field, which is the Currancy Name
namespace WebApplication2
{
public class DataHelper
{
public static string GetCurrency(string currencyCode)
{
string currencyName = "";
SqlConnection con = new SqlConnection(#"Data Source=WEB3\SHAREPOINT;Initial Catalog=WSS_Search_WEB3;Integrated Security=True");
SqlCommand cmd = new SqlCommand("select PO_NUMBER,PO_STATUS from View_1 where PO_HEADER_ID ='" + currencyCode.ToUpper() + "'", con);
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
currencyName = dr["PO_NUMBER"].ToString();
}
dr.Close();
con.Close();
return currencyName;
}
}
}
I need to get the PO_Number & PO Status from the Query
As I understand you need to return not only PO_NUMBER, but also PO_STATUS, and as I understand you want to return both values.
I suggest you make model that represent what you want to return.
So for that we make a model class call it for instance POModel:
public class POModel
{
public string currencyName { get; set; } // PO_Number
public string statusName { get; set; } // PO_Status
}
Than fetch the values from SQL as you did and return object in stead of string.
Here would you final code looks like, of course naming and all the stuff you can change the way if fits best:
public class DataHelper
{
public static POModel GetCurrency(string currencyCode)
{
//string currencyName = "";
var poModel = new POModel();
SqlConnection con = new SqlConnection(#"Data Source=WEB3\SHAREPOINT;Initial Catalog=WSS_Search_WEB3;Integrated Security=True");
SqlCommand cmd = new SqlCommand("select PO_NUMBER,PO_STATUS from View_1 where PO_HEADER_ID ='" + currencyCode.ToUpper() + "'", con);
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
poModel.currencyName = dr["PO_NUMBER"].ToString();
poModel.statusName = dr["PO_STATUS"].ToString();
}
dr.Close();
con.Close();
//return currencyName;
return poModel;
}
}
public class POModel
{
public string currencyName { get; set; }
public string statusName { get; set; }
}
One option is to return an array that contains the two values. Notice string[]:
public static string[] GetCurrency(string currencyCode)
Similar to how you declared string currencyName = "";, instead make an array variable:
string[] poData = new string[2];
Since this looks like it should return a single row, I would not loop. Just do a Read():
dr.Read();
poData[0] = dr["PO_NUMBER"].ToString(); //poData[] will have to be declared in your method
poData[1] = dr["PO_STATUS"].ToString();
....
return poData;

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

Multiple Object use across class c#

I have three classes that hold data from an input form and then each submit an insert query to the database.
There must be a better way of doing this with using the existing objects and a singular stored procedure, but I can't get the existing objects to work in another class. I apologise for the simplicity of the question as I imagine this to be a very straightforward fix to tidy up my code.
With the code below what I am trying to achieve is to reuse the existing instances of EndUser, Bank and Company in the StoredProc class so I don't have to use SQL queries in each class method and only one save method from the StoredProc class.
Edit
To clarify the database stuff ie the SQL string isn't the issue, what I am trying to ask is can I use instances of existing objects (three of them) in the storedproc class so I can use one (already written) stored procedure?
Apologies the code is a bit long but I have thinned it down as much as possible whilst still making sense (as well as running):
Form backend
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EndUser newUser = new EndUser(textBox1.Text, textBox2.Text);
Company newcmpny = new Company(textBox4.Text, textBox3.Text);
Bank newbank = new Bank(textBox6.Text, textBox5.Text);
newUser.Save();
newcmpny.Save();
newbank.Save();
}
}
DataHold classes (all in one file)
class EndUser
{
public EndUser(string first, string last) {
firstName = first;
lastName = last;
}
public int iD { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
public void Save()
{
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["TestDatabase"].ConnectionString))
{
string sqlQuery = (#"INSERT INTO [EndUser] (FirstName, LastName)
VALUES (#FirstName, #LastName)");
connection.Open();
using (SqlCommand command = new SqlCommand(sqlQuery, connection))
{
command.Parameters.AddWithValue("FirstName", firstName).ToString();
command.Parameters.AddWithValue("LastName", lastName).ToString();
command.ExecuteNonQuery();
}
}
}
}
class Company
{
public Company(string cmpny, string tele)
{
company = cmpny;
telephone = tele;
}
public string company { get; set; } // textbox4
public string telephone { get; set; } // textbox3
public void Save()
{
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["TestDatabase"].ConnectionString))
{
string sqlQuery = (#"INSERT INTO [Company] (CName, Telephone)
VALUES (#CName, #Telephone)");
connection.Open();
using (SqlCommand command = new SqlCommand(sqlQuery, connection))
{
command.Parameters.AddWithValue("CName", company).ToString();
command.Parameters.AddWithValue("Telephone", telephone).ToString();
command.ExecuteNonQuery();
}
}
}
}
class Bank
{
public Bank(string bn, string scode)
{
name = bn;
sortcode = scode;
}
public string name { get; set; } // textbox6
public string sortcode { get; set; } // textbox5
public void Save()
{
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["TestDatabase"].ConnectionString))
{
string sqlQuery = (#"INSERT INTO [Bank] (BankName, SortCode)
VALUES (#BankName, #SortCode)");
connection.Open();
using (SqlCommand command = new SqlCommand(sqlQuery, connection))
{
command.Parameters.AddWithValue("BankName", name).ToString();
command.Parameters.AddWithValue("SortCode", sortcode).ToString();
command.ExecuteNonQuery();
}
}
}
}
class StoredProc
{
public void ToTheDB()
{
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["TestDatabase"].ConnectionString))
{
con.Open();
using(SqlCommand cmd = new SqlCommand("Procedure",con))
{
cmd.CommandType = CommandType.StoredProcedure;
// cmd.Parameters.AddWithValue("FirstName", newUser.firstName);
cmd.ExecuteNonQuery();
}
}
}
}
}
First of all - IMO it's a badly written code.
My advises:
Do not mix the models and SQL queries or any database logic.
Do not use plain SQL in C# code, but rather use Entity Framework or Stored Procedures.
Do not save multiple entities which share the same business logic without wrapping them with single transaction.
You have asked: "can I use instances of existing objects (three of them) in the storedproc class so I can use one (already written) stored procedure"
The answer is - you can hardly use the existing code in that way. You don't have the stored procedure as far as I can see. You have just strings with SQL queries.
Anyway, you can try to use your classes as models in storedproc class and create new stored procedure which uses them.
It should look something like this:
class StoredProc
{
public void ToTheDB(EndUser endUser, Company company, Bank bank)
{
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["TestDatabase"].ConnectionString))
{
con.Open();
using(SqlCommand cmd = new SqlCommand("Procedure",con))
{
cmd.CommandType = CommandType.StoredProcedure;
//Here you can use data from your "model" classes and add them as parameters for your stored procedure.
cmd.Parameters.Add("#FirstName", SqlDbType.VarChar).Value = endUser.firstName;
//the rest of the parameters from EndUser, Company and Bank classes
cmd.ExecuteNonQuery();
}
}
}
}
Once again, you should separate your logic and models.
It's an example model:
public class Bank
{
public string name { get; set; }
public string sortCode { get; set; }
}
Ant this is method of Data Access Layer or Repository:
void AddBank(Bank bank)
{
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["TestDatabase"].ConnectionString))
{
con.Open();
//Procedure for inserting
using(SqlCommand cmd = new SqlCommand("Procedure",con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Name", SqlDbType.VarChar).Value = bank.name;
cmd.ExecuteNonQuery();
}
}
}
A lot of design principles actually shy away from doing CRUD operations in the objects nowadays, preferring to accept the object as an argument to a data service layer. Your code should actually be larger, not smaller. An example service would be:
public Bank(string bn, string scode)
{
name = bn;
sortcode = scode;
}
public string name { get; set; } // textbox6
public string sortcode { get; set; } // textbox5
}
class BankDataService
{
public void SaveNewBankToDatabase(Bank bank) {
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["TestDatabase"].ConnectionString))
{
string sqlQuery = (#"INSERT INTO [Bank] (BankName, SortCode)
VALUES (#BankName, #SortCode)");
connection.Open();
using (SqlCommand command = new SqlCommand(sqlQuery, connection))
{
command.Parameters.AddWithValue("BankName", bank.name);
command.Parameters.AddWithValue("SortCode", bank.sortcode);
command.ExecuteNonQuery();
}
}
}
public void UpdateBankToDatabase(Bank bank) {
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["TestDatabase"].ConnectionString))
{
string sqlQuery = (#"UPDATE [Bank]
SET SortCode=#SortCode
WHERE #BankName=#BankName");
connection.Open();
using (SqlCommand command = new SqlCommand(sqlQuery, connection))
{
command.Parameters.AddWithValue("BankName", bank.name);
command.Parameters.AddWithValue("SortCode", bank.sortcode);
command.ExecuteNonQuery();
}
}
}
public void SelectBankFromDatabase(string bankName) {
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["TestDatabase"].ConnectionString))
{
string sqlQuery = (#"SELECT BankName, SortCode FROM [Bank] WHERE BankName=#BankName");
connection.Open();
using (SqlCommand command = new SqlCommand(sqlQuery, connection))
{
command.Parameters.AddWithValue("BankName", bank.name);
using(var reader = command.ExecuteReader()) {
if(reader.Read()){
return new Bank { BankName=reader["BankName"].ToString(), SortCode=reader["SortCode"].ToString(); }
}
}
}
return null;
}
}
}

Return Object in C#

I'm trying to return an object in C#. In JavaScript, I would do this:
function myFunction () {
var myObj = { firstName: "John", lastName: "Smith", age: 20};
return myObj;
}
Everything I'm reading about returning an object within C# is much different than this so it's throwing me for a loop.
What I want to do is run a query to SQL to get some user info and return the users Role, Full Name, Email, etc...
Here is my current C# Code:
public static string getUserRole(string connectionString, string userId)
{
string role;
SqlConnection sqlCon = new SqlConnection(connectionString);
SqlCommand sqlCom = new SqlCommand();
SqlDataReader reader;
sqlCom.CommandText = "SELECT Role FROM myDatabase.Table WHERE Email = '" + userId + "'";
sqlCom.CommandType = CommandType.Text;
sqlCom.Connection = sqlCon;
sqlCon.Open();
reader = sqlCom.ExecuteReader();
if (reader.Read())
{
role = reader.GetString(0);
sqlCon.Close();
return role;
}
else
{
return "An error has occurred";
}
}
I'm assuming I need to do something like the following but it doesn't work:
public static string getUserRole(string connectionString, string userId)
{
string role;
string fullName;
string email;
SqlConnection sqlCon = new SqlConnection(connectionString);
SqlCommand sqlCom = new SqlCommand();
SqlDataReader reader;
sqlCom.CommandText = "SELECT Role FROM myDatabase.Table WHERE Email = '" + userId + "'";
sqlCom.CommandType = CommandType.Text;
sqlCom.Connection = sqlCon;
sqlCon.Open();
reader = sqlCom.ExecuteReader();
if (reader.Read())
{
public class myObject
{
role = reader.GetString(0);
fullName = reader.GetString(1);
email = reader.GetString(2);
}
sqlCon.Close();
return myObject;
}
else
{
return "An error has occurred";
}
}
I'm probably way off but from what I'm reading, object within c# are basically classes. So that makes sense. I need to create a class that defines my properties. Is this correct? I've ready lots of posts and watched some youtube videos but none are 'clicking'
Thanks in advance for any helpful input.
public class UserInfo
{
public string role;
public string fullName;
public string email;
public string ErrorCode;
}
and then change signatures to
public static UserInfo getUserRole(string connectionString, string userId)
and then change
if (reader.Read())
{
public class myObject
{
role = reader.GetString(0);
fullName = reader.GetString(1);
email = reader.GetString(2);
}
sqlCon.Close();
return myObject;
}
else
{
return "An error has occurred";
}
to create an object of UserInfo and return that. Like,
UserInfo info = new UserInfo();
if (reader.Read())
{
info.role = reader.GetString(0);
info.fullName = reader.GetString(1);
info.email = reader.GetString(2);
sqlCon.Close();
}
else
{
info.ErrorCode = "An error has occurred";
}
return info;
Note: Not the best way to do it, but should get you going. Just to give you an idea.

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.

Categories