I have a class and my MysqlConnection is in there:
public class DB
{
private static MySqlConnection _Connection;
public static MySqlConnection Connection
{
get
{
if(_Connection == null)
{
string cs = string.Format("SERVER={0}; DATABASE={1}; UID={2}; PWD={3};", SERVER_ADRESS, DATABASE, UID, PWD);
_Connection = new MySqlConnection(cs);
}
if(_Connection.State == System.Data.ConnectionState.Closed)
try
{
MessageBox.Show("MySQL Connection ist geschlossen. Öffne Sie");
_Connection.Open();
}
catch(MySqlException ex)
{
switch (ex.Number)
{
case 0:
MessageBox.Show("Verbindung zum Server konnte nicht hergestellt werden.");
break;
case 1045:
MessageBox.Show("Ungültiger Benutzername/Passwort.");
break;
default:
MessageBox.Show(ex.Message);
break;
}
}
return _Connection;
}
}
}
So i can use this connection in all the other classes with DB.Connection.
But now I get "DataReader is already open".
But all my DataReader's are in usings.
We start at my login page:
using (loginreader = cmd.ExecuteReader())
{
if (loginreader.Read())
{
DB.Connection.Close();
return true;
}
else
{
DB.Connection.Close();
return false;
}
loginreader.Close();
}
I guess this doesn't work. But the first Error Message after log in i get on another class on line 83:
DataTable schema = null;
using (var schemaCommand = new MySqlCommand("SELECT * FROM " + firmCustomerTablename, connection))
{
using (var reader = schemaCommand.ExecuteReader(CommandBehavior.SchemaOnly))
{
schema = reader.GetSchemaTable();
}
}
which is in a using too. So I don't understand why I get this Error. I guess closing the connections / the DataReaders dont work.
Before this change, i had a connection for every site. But my program had no good performance. So I decided to make 1 connection which is always Open and just call querys to this open connection. And now I get DataReader Errors.
Can someone explain me, why using is not closing the DataReader? And line 83 isn't a DataReader it's a var so i don't know why I get this Error at this line.
It sounds like your issues are regarding connection state management? I may not be fully understanding what you're asking but by design using statements within the context of connections will close the connection. They are syntactic sugar for try {} catch {} finally. Far too often I see examples of Connection objects, Command Objects, etc. not utilizing IDisposable and not being properly disposed/closed.
In this code, I don't see a connection being opened again for the command to execute.
DataTable schema = null;
using (var schemaCommand = new MySqlCommand("SELECT * FROM " + firmCustomerTablename, connection))
{
using (var reader = schemaCommand.ExecuteReader(CommandBehavior.SchemaOnly))
{
schema = reader.GetSchemaTable();
}
}
Here is a basic idea:
using (var conn = new SqlConnection(connectionString: ""))
{
conn.Open();
using (var cmd = new SqlCommand(cmdText: "cmdText", connection: conn))
{
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
//
}
}
}
}
Documentation: MSDN SqlConnection Class
Related
I'm trying to figure out how to setup my database access correctly while using the SqlClient hitting a Microsoft SQL Server. For the most part it is working, but there's a particular scenario that is giving me trouble. Namely: attempting to simultaneously use two connections in the same thread; one with an open data reader and the other performing a delete operation.
The following code demonstrates my conundrum:
public class Database {
...
internal SqlConnection CreateConnection() => new SqlConnection(connectionString);
...
}
public IEnumerable<Model> GetModel() {
var cmd = new SqlCommand() { ... };
using(var conn = db.CreateConnection()) {
conn.Open();
cmd.Connection = conn;
using(var reader = cmd.ExecuteReader()) {
while(reader.Read()) {
var m = new Model();
// deserialization logic
yield return m;
}
}
}
}
public void Delete(int id) {
var cmd = new SqlCommand() { ... }
using(var conn = db.CreateConnection()) {
conn.Open(); // throwing the error here
cmd.Connection = conn;
cmd.ExecuteNonQuery();
}
}
Application Code:
using(var scope = new TransactionScope()) {
var models = GetModels();
foreach(var m in models) {
Delete(m.Id); // throws an exception
}
scope.Complete();
}
For whatever reason, an exception is thrown by the above code while trying to execute the Delete operation:
quote
System.Transactions.TransactionAbortedException: The transaction has aborted. ---> System.Transactions.TransactionPromotionException: Failure while attempting to promote transaction. ---> System.Data.SqlClient.SqlException: There is already an open DataReader associated with this Command which must be closed first. ---> System.ComponentModel.Win32Exception: The wait operation timed out
quote
Now, I have confirmed that if I either set MultipleActiveResultSets=true or Pooling=false on the ConnectionString, that then the above application code will work without error. However, it doesn't seem like I should need to set either of those. If I open two connections simultaneously, should they not be separate connections? Why then am I getting an error from the Delete connection saying that there's an open DataReader?
Please help <3
By far the easiest fix here is to simply load all the models outside the transaction before you go deleting any. Eg
var models = GetModels().ToList();
using(var scope = new TransactionScope()) {
foreach(var m in models) {
Delete(m.Id); // throws an exception
}
scope.Complete();
}
Even fetching the models inside the transaction shold work
using(var scope = new TransactionScope()) {
var models = GetModels().ToList();
foreach(var m in models) {
Delete(m.Id); // throws an exception
}
scope.Complete();
}
so long as you don't leave the connection open during the iteration. If you allow the connection in GetModels() to close, it will be returned to the connection pool, and be available for use for subsequent methods that are enlisted in the same transaction.
In the current code the connection in GetModels() is kept open during the foreach loop and Delete(id) has to open a second connection and try to create a distributed transaction, which is failing.
Without MultipleActiveResultsets, the GetModels connection can't be promoted to a distributed transaction in the middle of returning query results. Setting pooling=false will not make this error go away.
Here's a simplified repro to play with:
using Microsoft.Data.SqlClient;
using System.Collections.Generic;
using System.Transactions;
namespace SqlClientTest
{
class Program
{
static void Main(string[] args)
{
Setup();
var topt = new TransactionOptions();
topt.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
using (new TransactionScope(TransactionScopeOption.Required, topt ))
{
foreach (var id in GetIds())
{
Delete(id);
}
}
}
static string constr = #"server=.;database=tempdb;Integrated Security=true;TrustServerCertificate=true;";
public static void Setup()
{
using (var con = new SqlConnection(constr))
{
con.Open();
var cmd = con.CreateCommand();
cmd.CommandText = "drop table if exists ids; select object_id id into ids from sys.objects";
cmd.ExecuteNonQuery();
}
}
public static IEnumerable<int> GetIds()
{
using (var con = new SqlConnection(constr))
{
con.Open();
var cmd = con.CreateCommand();
cmd.CommandText = "select object_id id from sys.objects";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
yield return reader.GetInt32(0);
}
}
}
}
public static void Delete(int id)
{
using (var con = new SqlConnection(constr))
{
con.Open();
var cmd = con.CreateCommand();
cmd.CommandText = "insert into ids(id) values (#id)";
cmd.Parameters.Add(new SqlParameter("#id", id));
cmd.ExecuteNonQuery();
}
}
}
}
And here's what Profiler shows when run:
The main reason here as far as I understand is your yielding iteration.
So the DB connection has not yet called disposed as it's still being used in your iteration (foreach). If for example, you called .ToList() at that point it should return all the entries and then dispose of the connection.
See here for a better explanation on how yield works in an iteration: https://stackoverflow.com/a/58449809/3329836
I have a problem with my MySQL Reader - I am running the reader in a loop, checking if a configured entry exists in my database. After the reader is applied, the reader is getting closed and set to null again.
Anyhow, I always get this error message when I am running the "CheckExistEntry" - function in my code.
"07.04.2021 14:28:05 ERROR: There is already an open Data Reader associated with this connection which must be closed first."
The error does not occur in the following situations:
If I set a breakpoint at the relevant position in the code, the error does not occur.
If I set a sleep for 1000 MS before the reader is executed, the error does not occur.
Is it possible that C# is running loops via multithreading without me knowing it?
Here's the code:
public bool CheckExistEntry(string iColumnName)
{
MySqlDataReader reader = null;
string query2 = "SHOW COLUMNS FROM defectdetection.defects_main";
MySqlCommand cmd = new MySqlCommand(query2, MySqlConn);
try
{
// SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA =[Database Name] AND TABLE_NAME =[Table Name];#
// write_Log()
write_Log(log_directory, log_file, "BEFORE ExecuteReader");
//COMMENT FOR STACKOVERFLOW: cmd.ExecuteReader() triggers the Error.
reader = cmd.ExecuteReader();
write_Log(log_directory, log_file, "AFTER ExecuteReader");
//now, communication with MySQL is finished. ..
List<string> ColumnNames = new List<string>();
while (reader.Read())
{
ColumnNames.Add((string)reader[0]);
}
if (ColumnNames.Contains(iColumnName))
{
reader.Close();
reader.Dispose();
reader = null;
return true;
}
else
{
reader.Close();
reader.Dispose();
reader = null;
return false;
}
}
catch (Exception ex)
{
if (reader != null)
{
reader.Close();
reader.Dispose();
reader = null;
}
exception = new ArgumentException(ex.Message);
MessageBox.Show(ex.Message);
//TODO handle exception
write_Log(log_directory, log_file,"ERROR: There is already an open Data Reader associated with this connection which must be closed first.");
progressBarForm.Invoke(new updatebar(progressBarForm.Close));
return false;
}
}
i tried it with a triple-using statement now (using MySqlConnection, using MySqlCommand, using MySqlDatareader). But it still does not work, i get another error now: "Connection must be valid and open."
using (MySqlConnection MySqlConnLocal = new MySqlConnection()) {
using (MySqlCommand cmd = new MySqlCommand(query2, MySqlConnLocal)) {
using (MySqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
ColumnNames.Add((string)reader[0]);
}
}
if (ColumnNames.Contains(iColumnName))
{
return true;
}
else
{
return false;
}
}
}
FIXED IT NOW: This Code here was the solution:
//System.Threading.Thread.Sleep(1);
using (MySqlConnection MySqlConnLocal = new MySqlConnection(ConnString))
{
MySqlConnLocal.Open();
using (MySqlCommand cmd2 = new MySqlCommand(query2, MySqlConnLocal))
{
reader = cmd2.ExecuteReader();
while (reader.Read())
{
ColumnNames.Add((string)reader[0]);
}
}
}
You haven't dispose of "cmd". Try the following:
...
public bool CheckExistEntry(string iColumnName)
{
string query2 = "SHOW COLUMNS FROM defectdetection.defects_main";
try
{
using (MySqlConnection mySqlConn = new MySqlConnection(ConnectionStr))
{
mySqlConn.Open();
using (MySqlCommand cmd = new MySqlCommand(query2, mySqlConn))
{
using (MySqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
if ((string)reader[0] == iColumnName)
{
return true;
}
}
}
}
}
}
catch (Exception ex)
{
var exception = new ArgumentException(ex.Message);
MessageBox.Show(ex.Message);
//TODO handle exception
write_Log(log_directory, log_file, "ERROR: There is already an open Data Reader associated with this connection which must be closed first.");
//ToDo: add any additional desired code
}
return false;
}
If in php we can do something like where $result is some query:
$result = mysql_query("SELECT * FROM student");
if (mysql_num_rows($results) !==0)
{
//do operation.
}
else
echo "no data found in databasae";
What is equivalent to this if I want to do this in C# language?please advise.
I have Created a full Console application using mysql. In your select query you are querying the whole table which is a bad idea. use limit to get only one result - this should be enough to determine if there are any rows in the table.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql;
using MySql.Data.MySqlClient;
namespace ConsoleApplication29
{
class Program
{
static void Main(string[] args)
{
if (AnyRows())
{
Console.WriteLine("There are rows in the database");
}
else
Console.WriteLine("no data found in database");
//This will pause the output so you can view the results. Otherwise you will see the dos screen open then close.
Console.Read();
}
//This is the Methos to call
public static bool AnyRows()
{
string connectionString = "Server=localhost;Database=test;Uid=root;Pwd=yourpassword;";
//Wrap this is using clause so you don't have to call connection close
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
string query = "select * from mytable limit 1";
using (MySqlCommand command = new MySqlCommand(query, connection))
{
MySqlDataReader reader = command.ExecuteReader();
return reader.HasRows;
}
}
}
}
}
assuming "results" is of type int
if(results != 0)
{
//do operation
}
else
{
Console.WriteLine("..."); //or output elsewhere
}
c# if else
add a reference to linq, and it gets really easy
var result = SomeDatabaseCall();
if (result.Any()){
// do something
}
if you want to filter the results even further, you can do that inside the Any
var result = SomeDatabaseCall();
if (result.Any(r => r.ID == SomeID)){ // ID can be replaced with any properties in your return model
// do something
}
I got the solution. It is actually very simple. BTW thanks for those who helping. This is the solution:
class DBConnect
{
private MySqlConnection connection;
private string server;
private string database;
private string uid;
private string password;
public DBConnect()
{
Initialize();
}
private void Initialize()
{
server = "your_server";
database = "your_db";
uid = "usr";
password = "pwd";
string connectionString;
connectionString = "SERVER=" + server + ";" + "DATABASE=" + database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";";
connection = new MySqlConnection(connectionString);
}
//open connection to database
private bool OpenConnection()
{
try
{
connection.Open();
return true;
}
catch (MySqlException ex)
{
//When handling errors, you can your application's response based on the error number.
//The two most common error numbers when connecting are as follows:
//0: Cannot connect to server.
//1045: Invalid user name and/or password.
switch (ex.Number)
{
case 0:
MessageBox.Show("Cannot connect to server. Contact administrator");
break;
case 1045:
MessageBox.Show("Invalid username/password, please try again");
break;
}
return false;
}
}
//Close connection
private bool CloseConnection()
{
try
{
connection.Close();
return true;
}
catch (MySqlException ex)
{
MessageBox.Show(ex.Message);
return false;
}
}
public void Select()
{
string query = "SELECT * FROM table";
//Open connection
if (this.OpenConnection() == true)
{
//Create Command
MySqlCommand cmd = new MySqlCommand(query, connection);
//Create a data reader and Execute the command
MySqlDataReader dataReader = cmd.ExecuteReader();
//Read the data in the database
if (dataReader.HasRows == true)
{
while (dataReader.Read())
{
//do retrieve data
}
}else
{
MessageBox.Show("There's no recods in the database");
}
}
}
}
It's best to use SELECT 1 instead of grabbing unnecessary data from the database to simply check for the existence of rows.
public static bool IsTableEmpty(string tableName)
{
string cs = "Server=localhost;Database=test;Uid=root;Pwd=sesame;";
using (var conn = new MySqlConnection(cs))
{
conn.Open();
string sql = string.Format("SELECT 1 FROM {0}", tableName);
using (var cmd = new MySqlCommand(sql, conn))
{
using (var reader = cmd.ExecuteReader())
{
return !reader.HasRows;
}
}
}
}
If you want to get the row count, then you'll need something like:
public static int GetTableRowCount(string tableName)
{
string cs = "Server=localhost;Database=test;Uid=root;Pwd=sesame;";
using (var conn = new MySqlConnection(cs))
{
conn.Open();
string sql = string.Format("SELECT COUNT(*) FROM {0}", tableName);
using (var cmd = new MySqlCommand(sql, conn))
{
return Convert.ToInt32(cmd.ExecuteScalar());
}
}
}
I am getting Database is locked exception from SQLite for some queries only.
Below is my code:
When I execute any select statement it works fine.
When I am executing any write statement on Jobs Table it also works fine.
This works fine:
ExecuteNonQuery("DELETE FROM Jobs WHERE id=1");
But the same way if I am executing queries for Employees table it is throwing an exception that database is locked.
This throws Exception:
ExecuteNonQuery("DELETE FROM Employees WHERE id=1");
Below are my functions:
public bool OpenConnection()
{
if (Con == null)
{
Con = new SQLiteConnection(ConnectionString);
}
if (Con.State == ConnectionState.Closed)
{
Con.Open();
//Cmd = new SQLiteCommand("PRAGMA FOREIGN_KEYS=ON", Con);
//Cmd.ExecuteNonQuery();
//Cmd.Dispose();
//Cmd=null;
return true;
}
if (IsConnectionBusy())
{
Msg.Log(new Exception("Connection busy"));
}
return false;
}
public Boolean CloseConnection()
{
if (Con != null && Con.State == ConnectionState.Open)
{
if (Cmd != null) Cmd.Dispose();
Cmd = null;
Con.Close();
return true;
}
return false;
}
public Boolean ExecuteNonQuery(string sql)
{
if (sql == null) return false;
try
{
if (!OpenConnection())
return false;
else
{
//Tx = Con.BeginTransaction(IsolationLevel.ReadCommitted);
Cmd = new SQLiteCommand(sql, Con);
Cmd.ExecuteNonQuery();
//Tx.Commit();
return true;
}
}
catch (Exception exception)
{
//Tx.Rollback();
Msg.Log(exception);
return false;
}
finally
{
CloseConnection();
}
}
This is the Exception:
At line 103 : Cmd.ExecuteNonQuery();
Exception Found:
Type: System.Data.SQLite.SQLiteException
Message: database is locked
database is locked
Source: System.Data.SQLite
Stacktrace: at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt)
at System.Data.SQLite.SQLiteDataReader.NextResult()
at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
at TimeSheet6.DbOp.ExecuteNonQuery(String sql) in d:\Projects\C# Applications\Completed Projects\TimeSheet6\TimeSheet6\DbOp.cs:line 103
Somewhere along the way a connection is getting left open. Get rid of OpenConnection and CloseConnection and change ExecuteNonQuery to this:
using (SQLiteConnection c = new SQLiteConnection(ConnectionString))
{
c.Open();
using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
{
cmd.ExecuteNonQuery();
}
}
Further, change the way you read data to this:
using (SQLiteConnection c = new SQLiteConnection(ConnectionString))
{
c.Open();
using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
{
using (SQLiteDataReader rdr = cmd.ExecuteReader())
{
...
}
}
}
Do not attempt, to manage connection pooling on your own like you are here. First, it's much more complex than what you have coded, but second, it's handled already inside the SQLiteConnection object. Finally, if you're not leveraging using, you're not disposing these objects properly and you end up with issues like what you're seeing now.
You can use 'using' statement as below, that will make sure connection & command disposed correctly even in exception
private static void ExecuteNonQuery(string queryString)
{
using (var connection = new SQLiteConnection(
ConnectionString))
{
using (var command = new SQLiteCommand(queryString, connection))
{
command.Connection.Open();
command.ExecuteNonQuery();
}
}
}
You should close your DataReader before attempting to write any data to the database. Use:
dr.Close();
after you finish using the DataReader.
In my case it was very stupid of me, I was making changes in SQLite browser and did not click on write changes, which locked the DB to be modified by the services. After I clicked the Write changes button, all the post request worked as expected.
A lot of helpful posts here for folks that may have forgotten to clean up a dangling connection, but there is another way this can happen: SQLite does not support concurrent INSERTs; if you issue two INSERTs at the same time the will be processed in serial. When the INSERTs are quick this is fine, but if an INSERT takes longer than the timeout the second INSERT can fail with this message.
I had this happen when I used a long running transaction to accumulate a bunch of INSERTs into one big commit. Basically I locked the database from any other activity during the transaction. Switching to journal_mode=WAL will allow concurrent writes and reads, but not concurrent writes.
I got rid of the long running transaction and let each INSERT autocommit, and that solved my problem.
Mine was caused by not closing a SqliteDataReader when calling HasRows().
I had this:
using (SQLiteConnection connection = new SQLiteConnection(DbPath))
{
connection.Open();
string sql = $"SELECT * FROM ...";
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{
return command.ExecuteReader().HasRows;
}
connection.Close();
}
But needed to put a using around the ExecuteReader like so:
using (SQLiteDataReader reader = command.ExecuteReader())
{
return command.ExecuteReader().HasRows;
}
Even though the DbConnection was being disposed and re-created each time the db was still being kept locked by the reader.
I was also getting the same error here:
if (new basics.HindiMessageBox(HMsg, HTitle).ShowDialog()==true)
{
SQLiteConnection m_dbConnection = new SQLiteConnection(MainWindow.con);
m_dbConnection.Open();
sql = "DELETE FROM `users` WHERE `id`=" + SelectedUser.Id;
command = new SQLiteCommand(sql, m_dbConnection);
command.ExecuteNonQuery();
m_dbConnection.Close();
LoadUserDG();
}
but when I just changed SQLiteConnection declaration location
public partial class User : Window
{
SQLiteCommand command;
string sql;
AddUser AddUserObj;
List<basics.users> usersList;
basics.users SelectedUser;
SQLiteConnection m_dbConnection;
// ...
private void DeleteBtn_Click(object sender, RoutedEventArgs e)
{
// ...
if (new basics.HindiMessageBox(HMsg, HTitle).ShowDialog()==true)
{
m_dbConnection = new SQLiteConnection(MainWindow.con);
m_dbConnection.Open();
sql = "DELETE FROM `users` WHERE `id`=" + SelectedUser.Id;
command = new SQLiteCommand(sql, m_dbConnection);
command.ExecuteNonQuery();
m_dbConnection.Close();
LoadUserDG();
}
}
Everything is fine now.
I hope this may work for you, too.
If someone can say how this happened, I would like to know the details to improve my knowledge, please.
I had the same issue when loading a lot of data to different tables from multiple threads.
When trying to do the inserts I was getting database locked because the program was doing too many insert too fast and SQLite didn't have time to complete each transaction before another one came.
The insert are done through threading because I didn't want the interface to be locked and wait for the insert to be done.
My solution is to use BlockingCollection with ThreadPool.QueueUserWorkItem.
This allows me to free the interface while doing the inserts.
All the insert are queued and executed in FIFO (First In First Out) order.
Now the database is never locked while doing any SQL transaction from any thread.
public class DatabaseQueueBus
{
private BlockingCollection<TransportBean> _dbQueueBus = new BlockingCollection<TransportBean>(new ConcurrentQueue<TransportBean>());
private CancellationTokenSource __dbQueueBusCancelToken;
public CancellationTokenSource _dbQueueBusCancelToken { get => __dbQueueBusCancelToken; set => __dbQueueBusCancelToken = value; }
public DatabaseQueueBus()
{
_dbQueueBusCancelToken = new CancellationTokenSource();
DatabaseQueue();
}
public void AddJob(TransportBean dto)
{
_dbQueueBus.Add(dto);
}
private void DatabaseQueue()
{
ThreadPool.QueueUserWorkItem((param) =>
{
try
{
do
{
string job = "";
TransportBean dto = _dbQueueBus.Take(_dbQueueBusCancelToken.Token);
try
{
job = (string)dto.DictionaryTransBean["job"];
switch (job)
{
case "SaveClasse":
//Save to table here
break;
case "SaveRegistrant":
//Save Registrant here
break;
}
}
catch (Exception ex)
{//TODO: Handle this exception or not
}
} while (_dbQueueBusCancelToken.Token.IsCancellationRequested != true);
}
catch (OperationCanceledException)
{
}
catch (Exception ex)
{
}
});
}
}
The inserts are done this way, but without the queuing I was still getting the lock issue.
using (SQLiteConnection c = new SQLiteConnection(BaseDal.SQLiteCon))
{
c.Open();
using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
{
cmd.ExecuteNonQuery();
}
c.Close();
}
I am using Visual Studio 2010 (C#) with mysqlConnector and everything seems to be fine.
However, when I try to request something from the server I get this error:
"There is already an open DataReader associated with this Connection which must be closed first."
This is my code:
gc.connect();
List<Conseiller> conseillers = gc.getAllConseillers();
--
public void connect()
{
string connStr = "SERVER=localhost;UID=root;DATABASE=Projet;Password=root";
oConn = new MySqlConnection(connStr);
try
{
oConn.Open();
Console.WriteLine("Successfully connected to the data base");
}
catch (OdbcException caugth)
{
/* Traitement de l'erreur */
Console.WriteLine(caugth.Message);
}
}
--
public List<Conseiller> getAllConseillers()
{
MySqlCommand oComm = oConn.CreateCommand();
oComm = oConn.CreateCommand();
Console.WriteLine("SELECT * FROM conseillers");
oComm.CommandText = "SELECT * FROM conseillers";
MySqlDataReader oReader = oComm.ExecuteReader(); // Error here
}
Where I am wrong ?
don't try to separate the connect with the get data. The call to Open may in-fact not go to the database at all and you will not detect issues at that point. Note the using statement to close the connection. add SEH as required
List<Conseiller> conseillers = gc.getAllConseillers();
public void getAll() {
string connStr = "SERVER=localhost;UID=root;DATABASE=Projet;Password=root";
using (oConn = new MySqlConnection(connStr))
using (MySqlCommand oComm = oConn.CreateCommand())
{
oConn.Open();
oComm.CommandText = "SELECT * FROM conseillers";
MySqlDataReader oReader = oComm.ExecuteReader(); // no Error here
// user reader here
} catch (OdbcException caugth) {
/* Traitement de l'erreur */
Console.WriteLine(caugth.Message);
}
}
You're not disposing of your objects, which basically means that your previous call to getAllConseillers, or a similar method, opened a data reader that is still open.
The following objects in your question are disposable (ie. implements IDisposable), you should dispose of them all:
MySqlConnection
MySqlCommand
MySqlDataReader
Basically, I would change the code as shown to this:
using (var gc = new Whatever())
{
gc.connect();
List<Conseiller> conseillers = gc.getAllConseillers();
}
--
public void connect()
{
string connStr = "SERVER=localhost;UID=root;DATABASE=Projet;Password=root";
oConn = new MySqlConnection(connStr);
try
{
oConn.Open();
Console.WriteLine("Successfully connected to the data base");
}
catch (OdbcException ex)
{
/* Traitement de l'erreur */
Console.WriteLine(ex.Message);
oConn.Dispose();
oConn = null;
// optional: throw;
}
}
--
public List<Conseiller> getAllConseillers()
{
using (MySqlCommand oComm = oConn.CreateCommand())
{
Console.WriteLine("SELECT * FROM conseillers");
oComm.CommandText = "SELECT * FROM conseillers";
using (MySqlDataReader oReader = oComm.ExecuteReader()) // No error here
{
// process the result in oReader here
return ...;
}
...
}
...
}
A few suggestions that may help:
First, in your code above you have called CreateCommand twice and don't need to.
Secon, you can instantiate your Command a little different to make this easier to read:
MySqlCommand oComm = new MySqlCommand("Select * from conseillers", oConn);
then call the ExecuteReader.
Third, your code above doesn't show when the connection is open. Are you sure it's open? Are you sure you haven't already called a data reader with the open connection and didn't close it?
Fourth, you should always open the connection as late as possible and close it as early as possible. The code you have seems like you are going to open the connection and leave it open but I'm not really sure of your intent.
I would suggest using the Using syntax:
Using connection As New SqlConnection(connectionString)
Dim command As New SqlCommand(queryString, connection)
connection.Open()
Dim reader As SqlDataReader = command.ExecuteReader()
Try
While reader.Read()
Console.WriteLine(String.Format("{0}, {1}", _
reader(0), reader(1)))
End While
Finally
' Always call Close when done reading.
reader.Close()
End Try
End Using
Modify the above code for your situation....