I have a form that checks whether values are in a database before adding them. Each field is in a different table, and to keep everything clean, I have a checkExists method for each field. Is there a way to have a separate method that connects to the database, so that I don't have to connect in every field method?
I'd like to do something like this so that my code is less messy:
public void SetConnection()
{
SqlConnection myConnection =
new SqlConnection("user id=[username];" +
"password=[password];" +
"server=[server];" +
"database=[db_name];");
try
{
myConnection.Open();
}
catch(Exception e)
{
Console.WriteLine("Unable to Connect");
}
}
public Boolean CheckData_Company(string[] items)
{
Class_DB set_conn = new Class_DB();
try
{
set_conn.SetConnection();
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
//check that item does not already exist
string query_string = "SELECT * FROM CR_Company WHERE ([CompanyName] = #companyName";
SqlCommand check_Company = new SqlCommand(query_string, set_conn);
check_Company.Parameters.AddWithValue("#CompanyName", items[0]);
int CompanyExist = (int)check_Company.ExecuteScalar();
if(CompanyExist > 0)
{
return true;
}
else
{
return false;
}
}
But I get a
local variable set_conn
Argument 2: Cannot Convert from Class_DB to System.Data.SqlClient.SqlConnection
I understand the error, so what can I do to return the correct value, or do I have to establish a connection within my CheckData_Comany() method?
Your method SetConnection should be returning SqlConnection back like:
public SqlConnection SetConnection()
{
SqlConnection myConnection = new SqlConnection("user id=[username];" +
"password=[password];" +
"server=[server];" +
"database=[db_name];");
try
{
myConnection.Open();
}
catch(Exception e)
{
Console.WriteLine("Unable to Connect");
}
return myConnection;
}
and then you can have something like:
SqlConnection connection = set_conn.SetConnection();
and then pass it in SqlCommand constructor as parameter :
SqlCommand check_Company = new SqlCommand(query_string, connection);
Your complete method implementation would become :
public Boolean CheckData_Company(string[] items)
{
bool Exists = false;
Class_DB set_conn = new Class_DB();
SqlConnection connection = null;
try
{
connection = set_conn.SetConnection();
//check that item does not already exist
string query_string = "SELECT * FROM CR_Company WHERE ([CompanyName] = #companyName";
SqlCommand check_Company = new SqlCommand(query_string, set_conn);
check_Company.Parameters.AddWithValue("#CompanyName", items[0]);
int CompanyExist = (int)check_Company.ExecuteScalar();
if(CompanyExist > 0)
Exists = true;
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
connection.Close();
}
return Exists;
}
and important thing to note is do not forget the close the connection finally by calling connection.Close(), otherwise it might cause eating up the resources that shouldn't happen when we are done with querying the database and we should release the resources occupied.
Related
Hi i am getting the following error while trying to update my database using c# asp.net.
Error:
Server Error in '/' Application.
The ConnectionString property has not been initialized.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The ConnectionString property has not been initialized.
Source Error:
Line 33: catch (Exception e)
Line 34: {
Line 35: throw e;
Line 36: }
Line 37: }
I am explaining my code below.
index.aspx.cs:
protected void reject_Click(object sender, EventArgs e)
{
//LinkButton lbtn = (LinkButton)(sender);
//lbtn.BackColor = System.Drawing.Color.Red;
GridViewRow grdrow = (GridViewRow)((LinkButton)sender).NamingContainer;
LinkButton lbtn = (LinkButton)grdrow.FindControl("accept");
LinkButton LRejectBtn = (LinkButton)grdrow.FindControl("reject");
// string status = grdrow.Cells[6].Text;
int healthId = int.Parse(lbtn.CommandArgument);
int result=0;
if (Convert.ToString(lbtn.BackColor) == "Color [Green]")
{
char updatedStatus = 'R';
result = objhealthCommentBL.updateStatusDetails(updatedStatus, healthId);
if (result == 1)
{
LRejectBtn.BackColor = System.Drawing.Color.Red;
lbtn.BackColor = System.Drawing.Color.WhiteSmoke;
ScriptManager.RegisterStartupScript(this, this.GetType(), "alert", "alert('Your status has updated successfully.')", true);
}
else
{
ScriptManager.RegisterStartupScript(this, this.GetType(), "alert", "alert('Your status couldnot updated')", true);
}
}
}
healthCommentBL.cs:
public int updateStatusDetails(char updatedStatus, int healthId)
{
int result;
try
{
result = objhealthCommentDL.updateStatusDetails(updatedStatus, healthId);
return result;
}
catch (Exception e)
{
throw e;
}
}
healthCommentDL.cs:
namespace DataAccess
{
public class healthCommentDL
{
SqlConnection con = new SqlConnection(CmVar.convar);
public DataSet getHealthCommentDetails()
{
try
{
con.Open();
DataSet ds = new DataSet();
string sql = "SELECT Health_Comment_ID,Health_ID,Health_Comment_Name,Health_comment_Email,Health_Comment_Message,Health_Comment_Website,Health_Comment_Status from T_Health_Comment";
sql += " order by Health_Comment_ID ASC ";
SqlCommand cmd = new SqlCommand(sql, con);
SqlDataAdapter objadp = new SqlDataAdapter(cmd);
objadp.Fill(ds);
return ds;
}
catch (Exception e)
{
throw e;
}
finally
{
con.Close();
con.Dispose();
}
}
public int updateStatusDetails(char updatedStatus, int healthId)
{
int result;
try
{
con.Open();
string query = "UPDATE T_Health_Comment SET Health_Comment_Status = #status WHERE Health_Comment_ID = #healthid";
SqlCommand cmd = new SqlCommand(query, con);
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#healthid", healthId);
cmd.Parameters.AddWithValue("#status", updatedStatus);
result = cmd.ExecuteNonQuery();
con.Close();
return result;
}
catch (Exception e)
{
throw e;
}
}
}
}
I am getting the above error in healthCommentBL.cs file in catch statement.Here i can say that the commentstring is properly working in the getHealthCommentDetails method in healthCommentDL.cs file but at the same time it is not working for the 2nd method of this file.Please help me to resolve this error.
When you write your connection as;
public class healthCommentDL
{
SqlConnection con = new SqlConnection(CmVar.convar);
It will be a field of healthCommentDL class, not a local variable. And it's properties (like ConnectionString) is not initialiazed. Instead of that, define your connections as a local variables in your methods. ADO.NET is pretty good at maintaining your connections as a local variables. Read: SQL Server Connection Pooling
public DataSet getHealthCommentDetails()
{
SqlConnection con = new SqlConnection(CmVar.convar);
and
public int updateStatusDetails(char updatedStatus, int healthId)
{
SqlConnection con = new SqlConnection(CmVar.convar);
A few things more;
You should always use parameterized sql. This kind of string concatenations are open for SQL Injection attacks.
Use using statement to dispose your connections and commands automatically instead of calling Close or Dispose methods manually.
Don't use AddWithValue method. It may generate unexpected and surprising results sometimes. Use Add method overloads to specify your parameter type and it's size.
First of all: I got my code running without using oop. I declared all my variables inside the same class and opened/closed the connection right before and after passing the query to the db. That worked! Now with some new experiences I tried to split my code into different classes. Now it wont work anymore.
It tells me "Connection must be valid and open". Enough text, here's my current code:
Services.cs
public static MySqlConnection conn // Returns the connection itself
{
get
{
MySqlConnection conn = new MySqlConnection(Services.ServerConnection);
return conn;
}
}
public static string ServerConnection // Returns the connectin-string
{
get
{
return String.Format("Server={0};Port=XXXX;Database=xxx;Uid=xxx;password=xxXxxXxXxxXxxXX;", key);
}
}
public static void DB_Select(string s, params List<string>[] lists)
{
try
{
MySqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.Text;
string command = s;
cmd.CommandText = command;
MySqlDataReader sqlreader = cmd.ExecuteReader();
while (sqlreader.Read())
{
if (sqlreader[0].ToString().Length > 0)
{
for (int i = 0; i < lists.Count(); i++)
{
lists[i].Add(sqlreader[i].ToString());
}
}
else
{
foreach (List<string> save in lists)
{
save.Add("/");
}
}
}
sqlreader.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error while selecting data from database!\nDetails: " + ex);
}
}
LoginForm.cs
private void checkUser(string username, string password)
{
using (Services.conn)
{
Services.conn.Open();
Services.DB_Select("..a short select statement..");
Services.conn.Close();
}
I guess this is all we need. I have shortened my code to get a focus on the problem.
I created Services.cs to get a global way to access the db from all forms without copy&pasting the connection info. Now when I reach my LoginForm.cs it throws an error "Connection must be valid and open". I've already debugged my code. It's all time closed. Even when passing conn.Open() it stays closed. Why?
Another try: I've also tried placing conn.Open() and conn.Close() inside Services.DB_Select(..) at the beginning and end. Same error here.
I have to say: The code worked before and I've used the same connection-string. So the string itself is surely valid.
I appreciate any help given here!
The problem is that you don't store the connection that was returned from your factory property. But don't use a property like a method. Instead use it in this way:
using (var con = Services.conn)
{
Services.conn.Open();
Services.DB_Select("..a short select statement..", con ));
//Services.conn.Close(); unnecessary with using
}
So use the same connection in the using that was returned from the property(or better created in the using) and pass it to the method which uses it. By the way, using a property as factory method is not best practise.
But in my opinion it's much better to create the connection where you use it, best place is in the using statement. And throw the con property to the garbage can, it is pointless and a source for nasty errors.
public static void DB_Select(string s, params List<string>[] lists)
{
try
{
using(var conn = new MySqlConnection(Services.ServerConnection))
{
conn.Open();
MySqlCommand cmd = conn.CreateCommand();
cmd.CommandText = s;
using( var sqlreader = cmd.ExecuteReader())
while (sqlreader.Read())
{
if (sqlreader[0].ToString().Length > 0)
{
for (int i = 0; i < lists.Count(); i++)
{
lists[i].Add(sqlreader[i].ToString());
}
}
else
{
foreach (List<string> save in lists)
{
save.Add("/");
}
}
} // unnecessary to close the connection
} // or the reader with the using-stetement
}
catch (Exception ex)
{
MessageBox.Show("Error while selecting data from database!\nDetails: " + ex);
}
}
Try to restructure your Services class as follows
public static MySqlConnection conn // Returns the connection itself
{
get
{
MySqlConnection conn = new MySqlConnection(Services.ServerConnection);
return conn;
}
}
private static string ServerConnection // Returns the connectin-string - PRIVATE [Improved security]
{
get
{
return String.Format("Server={0};Port=XXXX;Database=xxx;Uid=xxx;password=xxXxxXxXxxXxxXX;", key);
}
}
// Rather than executing result here, return the result to LoginForm - Future improvement
public static void DB_Select(MySqlConnection conn ,string s, params List<string>[] lists)
{
try
{
MySqlCommand cmd = conn.CreateCommand();
cmd.CommandType = CommandType.Text;
string command = s;
cmd.CommandText = command;
MySqlDataReader sqlreader = cmd.ExecuteReader();
while (sqlreader.Read())
{
if (sqlreader[0].ToString().Length > 0)
{
for (int i = 0; i < lists.Count(); i++)
{
lists[i].Add(sqlreader[i].ToString());
}
}
else
{
foreach (List<string> save in lists)
{
save.Add("/");
}
}
}
sqlreader.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error while selecting data from database!\nDetails: " + ex);
}
}
In LoginForm.cs use returning connection and store it there. When you need to execute query, use
MySqlConnection conn=Services.conn(); // Get a new connection
Services.DB_Select(conn,"..a short select statement.."); // Executing requirement
Services.conn.Close();
Additional - I suggest you need to return MySqlDataReader to LoginForm and handle results there
private MySqlConnection _conn;
public MySqlConnection conn // Returns the connection itself
{
get
{
if(_conn == null)
_conn = new MySqlConnection(Services.ServerConnection);
return _conn;
}
}
I am in the process of adding a new form to an already established Winforms application.
I have a DataGridView on my form and the relevant method in code behind which calls my dbAPI DataTable method. I have written the method with exactly the same code as many others used in the dbAPI class but for some reason it is not initialising the connection string...
public DataTable getMyTable()
{
//used for populating the DataGridView
SqlCommand _com = new SqlCommand(string.Format("select * from tab.myTable where Country = 'Angola' "), _conn);
_com.CommandTimeout = _command_timeout;
DataSet _ds = new DataSet();
SqlDataAdapter _adapt = new SqlDataAdapter();
try
{
_adapt.SelectCommand = _com;
int i = _adapt.Fill(_ds, "Asset_Transactions");
if (_ds.Tables.Count > 0)
{
return _ds.Tables[0];
}
else
{
return makeErrorTable("GetMyTable", "No Table Returned for myTable");
}
}
catch (Exception e)
{
return makeErrorTable("GetMyTable", e.Message);
}
}
_conn is an SQLConnection object. My connection string is in the app.config...
class dbAPI
{
Utils _utils = new Utils();
//this is the API between the Application Code and the LDB Database
string _ldb_connection_string = (string)dii.Properties.Settings.Default.connLDB; //connection string but with only one \ in settings as it gets converted to \\
int _command_timeout = Convert.ToInt32((string)dii.Properties.Settings.Default.commandTimeOut); //Command time out
SqlConnection _conn = new SqlConnection();
public dbAPI()
{
//constructor
}
#region --------------- Database Connectivity Section
public string openLocalDatabaseConnection()
{
try
{
//try to create the connection
_conn = new SqlConnection(_ldb_connection_string);
_conn.Open();
}
catch (Exception e)
{
return string.Concat("Can't connect to LDB with '", e.Message, "'");
}
return ""; //success
}
public string closeLocalDatabaseConnection()
{
_conn.Close();
_conn.Dispose();
return "";
}
I am getting an empty connection string and 'The ConnectionString property has not been initialized' exception thrown. I don't understand as I have numerous other methods in the class which work without issue. Any ideas?
Thanks
You have to call openLocalDatabaseConnection() function before proceeding further so that your SqlConnection Object will be initilised with Connection String Properly.
Code :
public DataTable getMyTable()
{
openLocalDatabaseConnection();
//used for populating the DataGridView
SqlCommand _com = new SqlCommand(string.Format("select * from tab.myTable where Country = 'Angola' "), _conn);
_com.CommandTimeout = _command_timeout;
DataSet _ds = new DataSet();
SqlDataAdapter _adapt = new SqlDataAdapter();
try
{
_adapt.SelectCommand = _com;
int i = _adapt.Fill(_ds, "Asset_Transactions");
if (_ds.Tables.Count > 0)
{
return _ds.Tables[0];
}
else
{
return makeErrorTable("GetMyTable", "No Table Returned for myTable");
}
}
catch (Exception e)
{
return makeErrorTable("GetMyTable", e.Message);
}
}
For example add an application config file to your project(or inside the one you have) and place this(the name and the connection string you place yours of course):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name ="MyConnection" connectionString ="your connection string here"/>
</connectionStrings>
</configuration>
Then in your _ldb_connection_string:
string _ldb_connection_string = ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString;
I have an application I'm trying to create, however I'm stuck.
I am trying to access the site's MySQL query within my code.
Right now I am just trying to test it, to make sure it works, but I'm having no luck with that.
I think I'm just overlooking something simple, but I'm not sure. Any help?
class DBConnect
{
private MySqlConnection connection;
private string server;
private string database;
private string uid;
private string password;
public List<string>[] list = new List<string>[1];
public DBConnect()
{
Initialize();
}
private void Initialize()
{
server = "localhost";
database = "XXX";
uid = "XXX";
password = "XXX";
string connectionString;
connectionString = "SERVER=" + server + ";" + "DATABASE=" + database
+ ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";";
connection = new MySqlConnection(connectionString);
}
//this will open the connection to MySql
private bool OpenConnection()
{
try
{
connection.Open();
return true;
}
//if there is a problem connecting, display one of the following connections
catch (MySqlException ex)
{
switch (ex.Number)
{
case 0:
MessageBox.Show("Cannot connect to server. Contact Admin");
break;
case 1045:
MessageBox.Show("Invalid username/password, please try again");
break;
}
return false;
}
}
//if the connection fails to connect to MySql server, the client will close the connection.
private bool CloseConnection()
{
try
{
connection.Close();
return true;
}
catch (MySqlException ex)
{
MessageBox.Show(ex.Message);
return false;
}
}
//Select statement
public List<string>[] Select()
{
int firstNumber = 2058;
**string query = "USE `db_order` SELECT `order_id` FROM `order_address` WHERE order_id=2058";**
//create a list to store the results
list[0] = new List<string>(0);
//Open's connection
if (this.OpenConnection() == true)
{
//creates a command from the query.
MySqlCommand cmd = new MySqlCommand(query, connection);
//creates a data reader, and executes the command.
MySqlDataReader dataReader = cmd.ExecuteReader();
while (dataReader.Read())
{
list[0].Add(dataReader["order_id"] + "");
}
//close Data Reader
dataReader.Close();
this.CloseConnection();
//returns list to be displayed
return list;
}
else
{
return list;
}
}
}
Here is the second class (i got rid of anything that isn't a part of the problem):
public partial class Form1
{
private void InitializeComponent()
{
// CustName
//
this.CustName.AutoSize = true;
this.CustName.Location = new System.Drawing.Point(200, 30);
this.CustName.Name = "CustName";
this.CustName.Size = new System.Drawing.Size(137, 13);
this.CustName.TabIndex = 0;
this.CustName.Text = "Customer\'s name goes here" + new DBConnect().list[0];
}
#endregion
}
Update
You add to the list from your DataReader like this
list[0].Add(dataReader["order_id"] + "");
So, which means you have a multi-dimensional (2-dimension to be exact) array of list. Therefore to access that you have to do like Select()[0][0] , check below:
DBConnect() DBCon = new DBConnect();
this.Custname.Text = DBCon.Select()[0].Count>0 ? "Customer\'s name goes here" +DBCon.Select()[0][0].ToString() : "No Customer to show";
I got a problem. I stack!
Don't know if i need a new class for it!
i want a methode for closing the connection via a Button click.
I already created the constructor:
public string Server;
public string Username;
public string Pwd;
public string DB;
MySqlConnection conn;
string ConnString;
public DBVerb(string eServer, string eUsername, string ePwd, string eDB)
{
this.Server = eServer;
this.Username = eUsername;
this.Pwd = ePwd;
this.DB = eDB;
}
And this two methods:
public void Connect(System.Windows.Forms.Label lblStatus)
{
try
{
ConnString = String.Format("server={0};user id={1}; password={2}; database={3}; pooling=false",
this.Server, this.Username, this.Pwd, this.DB);
conn = new MySqlConnection();
conn.ConnectionString = ConnString;
if (conn != null)
conn.Close();
conn.Open();
if (conn.State == ConnectionState.Open)
{
lblStatus.Text = String.Format("Verbindung zu {0} user: {1} Zeit: {2}", this.Server, this.Username, DateTime.Now.ToString());
}
else
{
MessageBox.Show("Felher");
}
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message, "Fehler:", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
public void ClConnect()
{
conn = new MySqlConnection();
if (conn.State == ConnectionState.Open)
{
conn.Close();
}
}
Here I'm calling the Methode:
private void cmdHerstellen_Click(object sender, EventArgs e)
{
string lServer = txtBServ.Text;
string lUID = txtBUid.Text;
string lPawd = txtBPass.Text;
string lDB = txtBDat.Text;
DBVerb VerbindungHerstellen = new DBVerb(lServer, lUID, lPawd, lDB);
VerbindungHerstellen.Err();
VerbindungHerstellen.Connect(lblStatus);
}
private void cmdAbbr_Click(object sender, EventArgs e)
{
}
If i call the Method ClConnect() than I have to give the arguments for the parameter, but I already did, so it don't work.
Any idea how to do it?
You are storing your dbconnection as a field in your class. When you want to close it you don't want to assign a new connection object to it with conn = new MySqlConnection(); and instead just want to remove that line and replace it with a check to see if conn is null or not. If its null then no work needs to be done (or maybe its an error) and if its not null then you can check if it is open and close if appropriate.
You probably also want to be careful of where you are creating new objects in the connect method. If conn already exists you probably don't want to (or need to) create a new connection object.
My last comment is that there is something wrong sounding about the user needing to click a button to close your connection. That should be soemthign the code worries about and not the user. However, I obviously don't know what you are doing with this so I can't say it is definitely wrong, just that it feels a bit wrong. :)