Multiple Object use across class c# - 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;
}
}
}

Related

How to pass data, select for an array

How to save the select data below into an array.
SqlConnection conConexao1 = clsdb.AbreBanco();
SqlCommand cmd1 = new SqlCommand("select id, tamplete1, tamplete2 from usuarios ", conConexao1);
SqlDataReader dr1 = cmd1.ExecuteReader();
if (dr1.HasRows == true)
{
if (dr1.Read())
{
id = int.Parse(dr1[0].ToString());
templete1 = (dr1[1].ToString());
templete2 = (dr1[2].ToString());
}
}
I have already tried using foreach, but always passes the last table data.
As a collection, List provide better flexibility than array.
The collection should be created outside the loop and the element should be added inside the loop.
List<Usuarios> list = new List<Usuarios>();
using (SqlConnection conConexao1 = clsdb.AbreBanco())
using (SqlCommand cmd1 = new SqlCommand(
"select id, tamplete1, tamplete2 from usuarios ", conConexao1))
using (SqlDataReader dr1 = cmd1.ExecuteReader())
{
while (dr1.Read())
{
list.Add(new Usuarios
{
Id = dr1.GetInt32(0),
Templete1 = dr1[1].ToString(),
Templete2 = dr1[2].ToString()
});
}
}
The class to imitate your data structure
public class Usuarios
{
public int Id { get; set; }
public string Templete1 { get; set; }
public string Templete2 { get; set; }
}
if for some reason, you have to use an array as collection
Usuarios[] array = list.ToArray();

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;

Using web service to retrieve more than one database column

I am trying to use a web service to retrieve data for more than one column. The code below works fine :
public string GetCustomerNameWithIDNumber(string id_number)
{
string fullname ="";
string id_type = "";
string id_number = "";
string dob = "";
using (SqlConnection cn = new SqlConnection(constring))
{
cn.Open();
string q = "select fullname, id_type, id_number, date_ofbirth from account_info where id_number = #id_number";
using (SqlCommand cmd = new SqlCommand(q, cn))
{
cmd.Parameters.AddWithValue("#id_number", id_number);
using (SqlDataReader rd = cmd.ExecuteReader())
{
while (rd.Read())
{
fullname = rd["fullname"].ToString();
id_type = rd["id_type"].ToString();
id_number = rd["id_number"].ToString();
dob = rd["date_ofbirth"].ToString();
bvn2 = rd["bvn"].ToString();
}
}
return fullname;
}
}
}
Which just gets the Full name alone, now suppose i want to get for more than just one database column, how do I go about it?
You will want to return a class. Here is a simple class I wrote to hold this data:
class Customer {
public string FullName { get; set; }
public string IdType { get; set; }
public string IdNumber { get; set; }
public string DateOfBirth { get; set; }
public string Bvn { get; set; }
}
Then this method returns that customer object:
public Customer GetCustomerNameWithIDNumber(string id_number) {
using (SqlConnection cn = new SqlConnection(constring)) {
cn.Open();
string q = "select fullname,id_type,id_number,date_ofbirth from account_info where id_number =#id_number";
using (SqlCommand cmd = new SqlCommand(q, cn)) {
cmd.Parameters.AddWithValue("#id_number", id_number);
using (SqlDataReader rd = cmd.ExecuteReader()) {
while (rd.Read()) {
return new Customer {
FullName = rd["fullname"].ToString(),
IdType= rd["id_type"].ToString(),
IdNumber = rd["id_number"].ToString(),
DateOfBirth = rd["date_ofbirth"].ToString(),
Bvn = rd["bvn"].ToString()
};
}
}
}
}
}
This code will return the first customer in the database matching the id_number

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.

Three-tier architecture implementation in Windows form application

I am trying to insert data into a database using a three-tier architecture, but I am stuck and I cannot proceed further.
This is my code
First is UI part:
public void assignField()
{
string maritalCondition = "";
string sex = "";
assignObj.Registered_Date = dateTimePicker1_Date.Value;
assignObj.First_Name = txt_FirstName.Text;
if (comboBox2_MaritalStatus.SelectedIndex == 0)
{
maritalCondition = "Single";
}
else
maritalCondition = "Married";
assignObj.Marital_Status = maritalCondition;
if (RadioButton_Male.Checked == true)
sex = "Male";
else
sex = "Female";
assignObj.Gender = sex;
this.txt_Age.Text = Convert.ToInt32(age).ToString();
}
private void btnRegister_Click(object sender, EventArgs e)
{
assignField();
}
Next is the middle tier:
public class CustomerDataType
{
private DateTime registered_Date;
private string first_Name;
private int age;
private string marital_Status;
private string gender;
public DateTime Registered_Date
{
get { return registered_Date; }
set { registered_Date = value; }
}
public string First_Name
{
get { return first_Name; }
set { first_Name = value; }
}
public int Age
{
get { return age; }
set { age = value; }
}
public string Marital_Status
{
get { return marital_Status; }
set { marital_Status = value; }
}
public string Gender
{
get { return gender; }
set { gender = value; }
}
public void insertInfo()
{
CustomerDataAccess insertObj = new CustomerDataAccess(Registered_Date, First_Name, Age, Marital_Status, Gender);
insertObj.insertCustomerInfo();
}
}
and last is the data access tier:
public class CustomerDataAccess
{
public CustomerDataAccess(DateTime Registered_Date, string First_Name, int Age, string Marital_Status, string Gender)
{
this.registrationDate = Registered_Date;
this.fName = First_Name;
this.userAge = Age;
this.marriageStatus = Marital_Status;
this.userGender = Gender;
}
SqlConnection con;
SqlCommand cmd;
DateTime registrationDate;
string fName = "";
int userAge;
string marriageStatus;
string userGender;
public void insertCustomerInfo()
{
try
{
con = new SqlConnection("Data Source=LAKHE-PC;Initial Catalog=Sahakari;Integrated Security=True");
con.Open();
cmd = con.CreateCommand();
cmd.CommandText = "sp_registerCust";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Registered_Date", SqlDbType.DateTime);
cmd.Parameters["#Registered_Date"].Value = registrationDate;
cmd.Parameters.Add("#First_Name", SqlDbType.VarChar);
cmd.Parameters["#First_Name"].Value = fName;
cmd.Parameters.Add("#Age", SqlDbType.Int.ToString());
cmd.Parameters["#Age"].Value = userAge;
cmd.Parameters.Add("#Marital_Status", SqlDbType.VarChar);
cmd.Parameters["#Marital_Status"].Value = marriageStatus;
cmd.Parameters.Add("#Gender", SqlDbType.VarChar);
cmd.Parameters["#Gender"].Value = userGender;
cmd.ExecuteNonQuery();
con.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Here with the stored procedure, there is no problem and and from SQL Server I can insert data into table easily. But from windows form, it does not insert data in table. Plz help me.
I'll do something like below
UI
CustomerHandler custHandler = new CustomerHandler();
// create Customer object and pass to insert method
if (custHandler.InsertCustomer(new Customer(){
FirstName = txt_FirstName.Text, Registered_Date =dateTimePicker1_Date.Value,
//decalare other parameters....
))
{
// insert Success, show message or update label with succcess message
}
In my BL
public class CustomerHandler
{
// in BL you may have to call several DAL methods to perform one Task
// here i have added validation and insert
// in case of validation fail method return false
public bool InsertCustomer(Customer customer)
{
if (CustomerDataAccess.Validate(customer))
{
CustomerDataAccess.insertCustomer(customer);
return true;
}
return false;
}
}
In MY DAL
// this is the class you going to use to transfer data across the layers
public class Customer
{
public DateTime Registered_Date { get; set; }
public string FirstName { get; set; }
//so on...
}
public class CustomerDataAccess
{
public static void insertCustomer(Customer customer)
{
using (var con = new SqlConnection("Data Source=LAKHE-PC;Initial Catalog=Sahakari;Integrated Security=True"))
using (var cmd = con.CreateCommand())
{
con.Open();
cmd.CommandText = "sp_registerCust";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Registered_Date", customer.Registered_Date);
cmd.Parameters.AddWithValue("#FirstName", customer.FirstName);
// so on...
cmd.ExecuteNonQuery();
}
}
internal static bool Validate(Customer customer)
{
// some validations before insert
}
}
Your middle tier consists of classes holding the values you require in properties. Instead of writing the data access manually, try using the Entity Framework (EF) which does that for you.
Here (at MSDN) you can find a quickstart example which shows you how you can use it.
Instead of mapping the fields manually and executing a query, the Entity Framework does that which means you just have to assign the values to the object's properties and call SaveChanges() - the SQL code is created and executed automatically by the EF.
For further reading, there is also a lot to find here (at Stackoverflow).

Categories