I have an application that need to check to the database if a particular code exists; if it does exist, then have to load the corresponding value of that code else return null.
I don't want to hit the database for each code(running about 200.000 codes ).
so i got this small app to test the app.conf
public static void setAppSetting(string key, string value)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(System.Reflection.Assembly.GetExecutingAssembly().Location);
if (config.AppSettings.Settings != null)
{
config.AppSettings.Settings.Remove(key);
}
config.AppSettings.Settings.Add(key, value);
config.Save(ConfigurationSaveMode.Modified);
}
public static string getAppSetting(string key)
{
try
{
Configuration config = ConfigurationManager.OpenExeConfiguration(System.Reflection.Assembly.GetExecutingAssembly().Location);
return config.AppSettings.Settings[key].ToString();
}
catch (Exception ex)
{
throw ex;
}
}
private static void loadKeysValues()
{
using (SqlConnection Gcon = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["constr"].ConnectionString))
{
//Open Connection
Gcon.Open();
using (SqlCommand sqlCmd = new SqlCommand("SELECT key,value FROM tables", Gcon))
{
using (SqlDataReader reader = sqlCmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
System.Console.WriteLine(reader.GetString(0) + " , " + reader.GetString(1));
setAppSetting(reader.GetString(0), reader.GetString(1));
}
}
} // End of SqlDataReader
} // end of SqlCommand
}
}
static void Main(string[] args)
{
System.Console.WriteLine("Loading.........");
loadKeysValues();
System.Console.WriteLine("Completed");
System.Console.WriteLine("Input a key to get its value");
var input = System.Console.Read().ToString();
System.Console.WriteLine(getAppSetting(input));
System.Console.ReadLine();
}
But I got an error with the getAppSetting() at this line:
return config.AppSettings.Settings[key].ToString();
Error: Object reference not set to an instance of an object.
Plz help
Make sure that the value isn't null.
Try this:
if (config.AppSettings.Settings.ContainsKey(key) &&
config.AppSettings.Settings[key] != null)
{
return config.AppSettings.Settings[key].ToString();
}
Most likely you're trying to access a setting that doesn't exist. You could handle that exception in your catch block and return null in that case.
ToString() method donĀ“t return the value, try with Value property:
return config.AppSettings.Settings[key].Value;
Related
How do I store the results from a mysql query for use in other classes most efficiently?
I've tried the following code, which executes properly and stores all data in reader as it should. Reading the DataReader here works fine if I want to!
public class DatabaseHandler
{
public void MySqlGetUserByName(string input_username, MySqlDataReader reader)
{
try
{
_database.Open();
string query = "SELECT * FROM users WHERE username = '#input'";
MySqlParameter param = new MySqlParameter(); param.ParameterName = "#input"; param.Value = input_username;
MySqlCommand command = new MySqlCommand(query, _database);
command.Parameters.Add(param);
reader = command.ExecuteReader();
_database.Close();
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
But when I try to read the same DataReader here, it is null and throws an exception (right after Debug6).
public class LoginHandler
{
public static void UserAuth(Client user, string input_username, string input_password)
{
DatabaseHandler dataBase = new DatabaseHandler();
MySqlDataReader dataReader = null;
dataBase.MySqlGetUserByName(input_username, dataReader);
Console.WriteLine("Debug6");
if (!dataReader.HasRows)
{
user.SendChatMessage("No match found.");
return;
}
while (dataReader.Read())
{
user.SetData("ID", (int)dataReader[0]);
user.SetData("username", (string)dataReader[1]);
user.SetData("email", (string)dataReader[2]);
user.SetData("password", (string)dataReader[3]);
}
dataReader.Close();
}
}
Please let me know how to make this work, or if there is a more efficient way of doing this without limiting the function of MySqlGetUserByName. The purpose of it is to input a name and a place to store all info from the match in the database.
Also, feel free to drop in any other suggestions that could make the code more efficient.
You could change your MySqlGetUserByName to return a User instance if all goes well, otherwise you return a null instance to the caller (Or you can thrown an exception, or you can set a global error flag in the DatabaseHandler class..., but to keep things simple I choose to return a null)
public class DatabaseHandler
{
public User MySqlGetUserByName(string input_username)
{
User result = null;
try
{
string query = "SELECT * FROM users WHERE username = #input";
using(MySqlConnection cnn = new MySqlConnection(......))
using(MySqlCommand command = new MySqlCommand(query, cnn))
{
cnn.Open();
command.Parameters.AddWithValue("#input", input_username);
using(MySqlDataReader dataReader = command.ExecuteReader())
{
if (dataReader.Read())
{
result = new User();
result.ID = Convert.ToInt32(dataReader[0]);
..... and so on with the other user properties ....
}
}
}
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
// Return the user to the caller. If we have not found the user we return null
return result;
}
}
In the same way the caller handles the situation
public class LoginHandler
{
public static void UserAuth(string input_username, string input_password)
{
DatabaseHandler dataBase = new DatabaseHandler();
User result = dataBase.MySqlGetUserByName(input_username);
// If we have not found the user we have a null in the variable
if(result == null)
{
// Send your message using a static method in the user class
// User.SendMessage("User with username {input_username} not found!");
}
else
{
// User ok. return it? or do something with its data?
}
}
}
I am throwing a new exception when a database row is not found.
Class that was called:
public ProfileBO retrieveProfileByCode(string profileCode)
{
return retrieveSingleProfile("profile_code", profileCode);
}
private ProfileBO retrieveSingleProfile(string termField, string termValue)
{
ProfileBO profile = new ProfileBO();
//Query string is temporary. Will make this a stored procedure.
string queryString = " SELECT * FROM GamePresenterDB.gp.Profile WHERE " + termField + " = '" + termValue + "'";
using (SqlConnection connection = new SqlConnection(App.getConnectionString()))
{
connection.Open();
SqlCommand command = new SqlCommand(queryString, connection);
SqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
profile = castDataReadertoProfileBO(reader, profile);
}
else
{
// No record was selected. log it and throw the exception (We'll log it later, for now just write to console.)
Console.WriteLine("No record was selected from the database for method retrieveSingleProfile()");
throw new InvalidOperationException("An exception occured. No data was found while trying to retrienve a single profile.");
}
reader.Close();
}
return profile;
}
However, when I catch the exception in the calling class, 'e' is now null. What am I doing wrong? I believe this works fine in Java, so C# must handle this differently.
Calling class:
private void loadActiveProfile()
{
try
{
ProfileBO profile = profileDAO.retrieveProfileByCode(p.activeProfileCode);
txtActiveProfileName.Text = profile.profile_name;
}
catch (InvalidOperationException e)
{
}
}
Now all the code has been put in the question, you can move the try catch outside of your 'loadActiveProfile' method and place it into 'retrieveSingleProfile'.
private void loadActiveProfile()
{
ProfileBO profile = profileDAO.retrieveProfileByCode(p.activeProfileCode);
txtActiveProfileName.Text = profile.profile_name;
}
removed the try catch^
private ProfileBO retrieveSingleProfile(string termField, string termValue)
{
try {
ProfileBO profile = new ProfileBO();
//Query string is temporary. Will make this a stored procedure.
string queryString = " SELECT * FROM GamePresenterDB.gp.Profile WHERE " + termField + " = '" + termValue + "'";
using (SqlConnection connection = new SqlConnection(App.getConnectionString()))
{
connection.Open();
SqlCommand command = new SqlCommand(queryString, connection);
SqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
profile = castDataReadertoProfileBO(reader, profile);
}
else
{
// No record was selected. log it and throw the exception (We'll log it later, for now just write to console.)
Console.WriteLine("No record was selected from the database for method retrieveSingleProfile()");
throw new InvalidOperationException("An exception occured. No data was found while trying to retrienve a single profile.");
}
reader.Close();
}
return profile;
}
catch(InvalidOperationException e)
{
}
}
Added try catch in the correct place.
You need to step into the catch block for e to be set to the thrown InvalidOperationException:
catch (System.InvalidOperationException e)
{
int breakPoint = 0; //<- set a breakpoint here.
//Either you reach the breakpoint and have an InvalidOperationException, or you don't reach the breakpoint.
MessageBox.Show(e.Message);
}
Also make sure that the InvalidOperationException you throw is actually a System.InvalidOperationException and not some custom type of yours called "InvalidOperationException".
Like #Clemens said, you need to show all the relevant code.
As a quick test, this works just fine:
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("Throwing error");
ThrowException();
}
catch (InvalidOperationException e)
{
Console.WriteLine(e.Message);
}
Console.ReadKey(true);
}
static void ThrowException()
{
throw new InvalidOperationException("Blah blah blah");
}
}
I have a strange problem:
Database: Firebird
Connection String:
Driver={Firebird/InterBase(r)driver};Dbname=xxx;CHARSET=NONE;UID=xxx;
PASSWORD=xxx
I use a set of ODBC classes to operation(select) the database table
when I loop the db records with OdbcDataReader.GetValue(), if some fields(char type) have no value(char_length()=0), it would get the last record field value; if fields has the value, it's ok(does not get the value from last record)
My code likes below:
var dr = this.SqlExecutor.Open(sql); //sql is String variable that stored the sql statement
while (dr.Read())
{
this.Logger.Info("-----Customer_Id: " + this.SqlReader.GetFieldAsString(dr, "Customer_Id") + " -----"); // this not duplicated because it's not empty
this.Logger.Info("-----Customer_Email: " + this.SqlReader.GetFieldAsString(dr, "Customer_email") + " -----"); //this would if some records has empty value
}
// the method SqlExecutor.Open(sql) and SqlReader.GetFieldAsString() please refer to below:
public IDataReader Open(string sql)
{
this.Logger.Debug("sql: " + sql);
if (this.reader != null && !this.reader.IsClosed)
{
this.reader.Close();
this.reader = null;
}
try
{
this.cmdForSelect.Connection = this.conn;
this.cmdForSelect.CommandTimeout = 120;
this.cmdForSelect.CommandText = sql;
this.cmdForSelect.Parameters.Clear();
foreach (var p in this.dbParameters)
{
this.cmdForSelect.Parameters.Add(p);
}
this.reader = cmdForSelect.ExecuteReader();
}
catch (Exception ex)
{
this.Logger.Error("There is an error: {0}", ex.Message);
this.Logger.Info("Error sql query:" + sql);
throw;
}
finally
{
this.ClearParameters();
}
return this.reader;
}
public string GetFieldAsString(IDataReader dr, string fieldName)
{
try
{
var value = dr.GetValue(dr.GetOrdinal(fieldName));
if (value == DBNull.Value)
{
return string.Empty;
}
return Convert.ToString(value);
}
catch
{
return string.Empty;
}
}
Besides, this case is fine on my computer, just happened on my customer's computer, I feel this does not matter with mycode, anyone know this, please help me, thanks a lot!!!
Assuming the actual code is not posted in your question; I think the problem is with re-initiation of the variable in the actual code. You need to revisit the code and check the IF-ELSE condition you have applied on the this.SqlReader.GetFieldAsString(dr, "Customer_email")
So this is a little bit code-ceptionlike.
I have a function that is checking the last ID in a table, this function is called within another function. At the end of that function, I have another function that's opening another datareader.
Error:
There is already an open Datareader associated with this connection which must be closed first.
getLastIdfromDB()
public string getLastIdFromDB()
{
int lastIndex;
string lastID ="";
var dbCon = DB_connect.Instance();
if (dbCon.IsConnect())
{
MySqlCommand cmd2 = new MySqlCommand("SELECT ID FROM `competitor`", dbCon.Connection);
try
{
MySqlDataReader reader = cmd2.ExecuteReader();
while (reader.Read())
{
string item = reader2["ID"].ToString();
lastIndex = int.Parse(item);
lastIndex++;
lastID = lastIndex.ToString();
}
}
catch (Exception ex)
{
MessageBox.Show("Error:" + ex.Message);
}
}
return lastID;
}
This function is later-on used in this function:
private void addPlayerBtn_Click(object sender, EventArgs e)
{
ListViewItem lvi = new ListViewItem(getLastIdFromDB());
.........................................^
... HERE
...
... irrelevant code removed
.........................................
var dbCon = DB_connect.Instance();
if (dbCon.IsConnect())
{
MySqlCommand cmd = new MySqlCommand("INSERT INTO `competitor`(`ID`, `Name`, `Age`) VALUES(#idSql,#NameSql,#AgeSql)", dbCon.Connection);
cmd.Parameters.AddWithValue("#idSql", getLastIdFromDB());
cmd.Parameters.AddWithValue("#NameSql", playerName.Text);
cmd.Parameters.AddWithValue("#AgeSql", playerAge.Text);
try
{
cmd.ExecuteNonQuery();
listView1.Items.Clear();
}
catch (Exception ex)
{
MessageBox.Show("Error:" + ex.Message);
dbCon.Connection.Close();
}
finally
{
updateListView();
}
}
}
What would be the best way for me to solve this problem and in the future be sure to close my connections properly?
UPDATE: (per request, included DB_connect)
class DB_connect
{
private DB_connect()
{
}
private string databaseName = "simhopp";
public string DatabaseName
{
get { return databaseName; }
set { databaseName = value; }
}
public string Password { get; set; }
private MySqlConnection connection = null;
public MySqlConnection Connection
{
get { return connection; }
}
private static DB_connect _instance = null;
public static DB_connect Instance()
{
if (_instance == null)
_instance = new DB_connect();
return _instance;
}
public bool IsConnect()
{
bool result = true;
try
{
if (Connection == null)
{
if (String.IsNullOrEmpty(databaseName))
result = false;
string connstring = string.Format("Server=localhost; database={0}; UID=root;", databaseName);
connection = new MySqlConnection(connstring);
connection.Open();
result = true;
}
}
catch (Exception ex)
{
Console.Write("Error: " + ex.Message);
}
return result;
}
public void Close()
{
connection.Close();
}
}
}
You are trying to have multiple open readers on the same connection. This is commonly called "MARS" (multiple active result sets). MySql seems to have no support for it.
You will have to either limit yourself to one open reader at a time, or use more than one connection, so you can have one connection for each reader.
My suggestion would be to throw away that singleton-like thingy and instead use connection pooling and proper using blocks.
As suggested by Pikoh in the comments, using the using clause indeed solved it for me.
Working code-snippet:
getLastIdFromDB
using (MySqlDataReader reader2 = cmd2.ExecuteReader()) {
while (reader2.Read())
{
string item = reader2["ID"].ToString();
lastIndex = int.Parse(item);
lastIndex++;
lastID = lastIndex.ToString();
}
}
Your connection handling here is not good. You need to ditch the DB_connect. No need to maintain a single connection - just open and close the connection each time you need it. Under the covers, ADO.NET will "pool" the connection for you, so that you don't actually have to wait to reconnect.
For any object that implements IDisposable you need to either call .Dispose() on it in a finally block, or wrap it in a using statement. That ensures your resources are properly disposed of. I recommend the using statement, because it helps keep the scope clear.
Your naming conventions should conform to C# standards. Methods that return a boolean should be like IsConnected, not IsConnect. addPlayerBtn_Click should be AddPlayerButton_Click. getLastIdFromDB should be GetlastIdFromDb or getLastIdFromDatabase.
public string GetLastIdFromDatabase()
{
int lastIndex;
string lastID ="";
using (var connection = new MySqlConnection(Configuration.ConnectionString))
using (var command = new MySqlCommand("query", connection))
{
connection.Open();
MySqlDataReader reader = cmd2.ExecuteReader();
while (reader.Read())
{
string item = reader2["ID"].ToString();
lastIndex = int.Parse(item);
lastIndex++;
lastID = lastIndex.ToString();
}
}
return lastID;
}
Note, your query is bad too. I suspect you're using a string data type instead of a number, even though your ID's are number based. You should switch your column to a number data type, then select the max() number. Or use an autoincrementing column or sequence to get the next ID. Reading every single row to determine the next ID and incrementing a counter not good.
I am trying to create a method that runs a query then reads the 2 values it returns then place them in the global variables so I can access them in another page. My question is what method should I use because I have two variables to set. Typically I pass the variables that I will be using but in this case I'm not. This main seem simple but I can't think of a way to get these values. I am not sure how to look this problem up to research it either. I have included the code below what I have attempted so far. Thank you for you help.
public string getTotals3()
{
WorkerData workerData = new WorkerData();
StringBuilder sqlString = new StringBuilder();
sqlString.Append("SELECT DISTINCT DataWin8Data, DataWin7Data ");
sqlString.Append("FROM Data ");
sqlString.Append("WHERE Number = 4");
SqlDataReader reader = null;
SqlConnection dbConn = App_Code.DBHelper.getConnection();
try
{
reader = App_Code.DBHelper.executeQuery(dbConn, sqlString.ToString(), null);
if (reader != null)
{
while (reader.Read())
{
workerData.TotalCases4 = reader["DataWin8Data"] != DBNull.Value ? reader["DataWin8Data"].ToString() : string.Empty;
workerData.TotalPercentage4 = reader["DataWin7Data"] != DBNull.Value ? reader["DataWin7Data"].ToString() : string.Empty;
}
}
else
throw new Exception("No records returned");
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (dbConn != null)
{
try { dbConn.Close(); dbConn.Dispose(); }
catch { }
}
if (reader != null)
{
try { reader.Close(); reader.Dispose(); }
catch { }
}
}
return workerData.ToString();
}
Don't use global variables. Return the values out of the method. The calling code should be in charge of placing those values wherever it needs. I recommend reading about Dependency Inversion Principle.
public WorkerData GetWorkerData()
{
...
using (SqlDataReader reader = ...)
{
if (reader.Read())
{
return new WorkerData
{
TotalCases4 = reader["DataWin8Data"] != DBNull.Value ? reader["DataWin8Data"].ToString() : string.Empty,
TotalCases3 = workerData.TotalPercentage4 = reader["DataWin7Data"] != DBNull.Value ? reader["DataWin7Data"].ToString() : string.Empty;
}
}
}
throw new ApplicationException("Could not retrieve worker data.");
}
From your calling class, simply do whatever you want with the return value:
WorkerData workerData = someClass.GetWorkerData();