Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Just 1st student rotating from java to C# here. When we were studying Java we were given this kind of SQL connection manager class thing, which is just basically just bunch of code to make it easier accessing it in different classes (It's written by my danish teacher and has some misspells/inside jokes, not sure):
public class DbConnection
{ //Constants used to get access to the database
//SQL Server
private static final String driver = "nope";
// private static final String driver = "nope";
private static final String databaseName = ";databaseName=nope";
//SQL Server
// private static String userName = ";user=sa";
private static String userName = "; user=nope";
private static String password = ";password=nope";
private DatabaseMetaData dma;
private static Connection con;
// an instance of the class is generetated
private static DbConnection instance = null;
// the constructor is private to ensure that only one object of this class is created
DbConnection()
{
String url = driver + databaseName + userName + password;
try{
//load af driver
//SQL Server
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
System.out.println("Load af class ok");
}
catch(Exception e){
System.out.println("Can not find the driver");
System.out.println(e.getMessage());
}//end catch
try{
//connection to the database
con = DriverManager.getConnection(url);
//set autocommit
con.setAutoCommit(true);
dma = con.getMetaData(); // get meta data
System.out.println("Connection to " + dma.getURL());
System.out.println("Driver " + dma.getDriverName());
System.out.println("Database product name " + dma.getDatabaseProductName());
}//end try
catch(Exception e){
System.out.println("Problems with the connection to the database");
System.out.println(e.getMessage());
System.out.println(url);
}//end catch
}//end constructor
//closeDb: closes the connection to the database
public static void closeConnection()
{
try{
con.close();
System.out.println("The connection is closed");
}
catch (Exception e){
System.out.println("Error trying to close the database " + e.getMessage());
}
}//end closeDB
//getDBcon: Get-method, returns the connection to the database
public Connection getDBcon()
{
return con;
}
//this method is used to get the instance of the connection
public static DbConnection getInstance()
{
if (instance == null)
{
instance = new DbConnection();
}
return instance;
}
public static void startTransaction()
{ try{
con.setAutoCommit(false);
}
catch(Exception e){
System.out.println("fejl start transaction");
System.out.println(e.getMessage());
}
}
public static void commitTransaction()
{ try{
con.setAutoCommit(true);
}
catch(Exception e){
System.out.println("fejl commit transaction");
System.out.println(e.getMessage());
}
}
public static void rollbackTransaction()
{ try{
con.rollback();
con.setAutoCommit(true);
}
catch(Exception e){
System.out.println("fejl rollback transaction");
System.out.println(e.getMessage());
}
}
}//end DbConnection
So to get used to C# for second year i thought of first of recreating this in C# and first of all: Is it good idea to have it in C#? I see many people just using
using(SqlConnection....){}
thing and I'm not sure how to implement autoCommits/Transaction rollbacks since for example transactions in C# are different classes
So far i made this little class:
class DbConnection
{
private const string DB_USER_ID = "user id=sa;";
private const string DB_USER_PASSWORD = "password=nope;";
private const string DB_SERVER_URL = #"server=localhost\SQLExpress1;";
private const string DB_NAME = "database=test; ";
private const string DB_TIME_OUT = "connection timeout=30";
private const string DB_TRUSTED_CONN = "Trusted_Connection=yes;";
private static SqlConnection myConnection = null;
private static DbConnection instance = null;
// private constructor to ensure that only object of this class is created
private DbConnection()
{
createConnection();
}
// Instantiates SqlConnection object
private void createConnection()
{
Console.WriteLine("Attempting to create connectiong...");
try
{
myConnection = new SqlConnection(DB_USER_ID +
DB_USER_PASSWORD +
DB_SERVER_URL +
DB_TRUSTED_CONN +
DB_NAME +
DB_TIME_OUT);
}
catch (Exception e)
{
Console.WriteLine("Problems with the connection to the database");
Console.WriteLine(e.Message);
}
}
private void openConnection()
{
try{
myConnection.Open();
Console.WriteLine("Connection succesfful!");
} catch(Exception e) {
Console.WriteLine(e.StackTrace);
}
}
public static void closeConnection()
{
try
{
myConnection.Close();
Console.WriteLine("Connection closed");
}
catch (Exception e)
{
Console.WriteLine("Problem closing connection");
Console.WriteLine(e.Message);
}
}
public SqlConnection getDBcon()
{
return myConnection;
}
public static DbConnection getInstance()
{
if (instance == null)
{
instance = new DbConnection();
}
return instance;
}
}
Man, that DbConnection class is bad stuff. Throw it away. In VB the author would have used ON ERROR RESUME NEXT.
The main problem is that errors are just thrown away. The program continues in a bad state.
Next problem is a static (globally shared) connection object. That's not thread-safe and if the connection ever breaks (network issue) it permanently breaks.
.NET has connection pooling. This class is something you don't need. Maybe you can write yourself a little helper to open a connection:
static SqlConnection CreateConnection() {
...
}
using (var conn = CreateConnection()) {
}
How much more simple can it be?
Related
I am currently working on a problem that involves abstract classes and stopwatches. I have two classes, SQL and Oracle. They both take a string for a connection code (this stuff doesn't actually do anything, but I am trying to make this a bit realistic). I want to start a stopwatch, then stop it in a different method - but the Timespan always says 00:00...
Am I accessing my parent class' properties correctly?
I have tried initializing my stopwatches and timespan in different places.
public class Program
{
public static void Main(string[] args)
{
// ConnectionManagement management = new ConnectionManagement();
// management.SetUpOptions();
}
}
public class ConnectionManagement
{
public void SetUpOptions()
{
while (true)
{
SqlConnection sqlGatherer = new SqlConnection("placeholder");
OracleConnection oracleGatherer = new OracleConnection("placeholder");
Console.WriteLine("1. Open an SQL connection.");
Console.WriteLine("2. Close an SQL connection.");
Console.WriteLine("3. Open an Oracle connection.");
Console.WriteLine("4. Close an SQL connection.");
string choice = Console.ReadLine();
if (choice == "1")
{
Console.WriteLine("Enter your connection string.");
string enteredConnectionString = Console.ReadLine();
sqlGatherer.ConnectionString = enteredConnectionString;
sqlGatherer.OpenConnection();
}
else if (choice == "2")
{
sqlGatherer.CloseConnection();
}
else if (choice == "3")
{
Console.WriteLine("Enter your connection string.");
string enteredConnectionString = Console.ReadLine();
oracleGatherer.ConnectionString = enteredConnectionString;
oracleGatherer.OpenConnection();
}
else if (choice == "4")
{
oracleGatherer.CloseConnection();
}
else
{
Console.WriteLine("That was not a valid option.");
}
}
}
}
public abstract class DataBaseConnection
{
public string ConnectionString { get; set; }
public TimeSpan Timeout { get; set; }
public Stopwatch OracleStoppy { get; set; }
public Stopwatch SqlStoppy { get; set; }
public abstract void OpenConnection();
public abstract void CloseConnection();
}
public class SqlConnection : DataBaseConnection
{
private bool CurrentConnection = false;
public SqlConnection()
{
Timeout = new TimeSpan();
SqlStoppy = new Stopwatch();
}
public SqlConnection(string connectionString)
{
Timeout = new TimeSpan();
SqlStoppy = new Stopwatch();
if (connectionString == null || String.IsNullOrWhiteSpace(connectionString))
{
throw new ArgumentException("Program has an invalid SQL connection string.");
}
else
{
this.ConnectionString = connectionString;
}
}
public override void OpenConnection()
{
if (CurrentConnection == true)
{
throw new Exception("A connection has already been established.");
}
else
{
Console.WriteLine("SQL connection established.");
SqlStoppy.Start();
CurrentConnection = true;
}
}
public override void CloseConnection()
{
if (CurrentConnection == false)
{
SqlStoppy.Stop();
TimeSpan reportedTimeout = Timeout;
Console.WriteLine("Connection closed. \nThe connection was active for {0}", reportedTimeout);
SqlStoppy.Reset();
CurrentConnection = false;
}
else
{
throw new Exception("There is no SQL connection to close.");
}
}
}
public class OracleConnection : DataBaseConnection
{
private bool CurrentConnection = false;
public OracleConnection()
{
Timeout = new TimeSpan();
OracleStoppy = new Stopwatch();
}
public OracleConnection(string connectionString)
{
Timeout = new TimeSpan();
OracleStoppy = new Stopwatch();
if (connectionString == null || String.IsNullOrWhiteSpace(connectionString))
{
throw new Exception("Program has an invalid Oracle connection string.");
}
else
{
this.ConnectionString = connectionString;
}
}
public override void OpenConnection()
{
if (CurrentConnection == true)
{
throw new Exception("A connection has already been established.");
}
else
{
Console.WriteLine("Oracle connection established.");
OracleStoppy.Start();
CurrentConnection = true;
}
}
public override void CloseConnection()
{
if (CurrentConnection == false)
{
throw new Exception("There is no Oracle connection to close.");
}
else
{
OracleStoppy.Stop();
this.Timeout = OracleStoppy.Elapsed;
Console.WriteLine("Connection closed. \nThe connection was active for {0}", Timeout);
OracleStoppy.Reset();
CurrentConnection = false;
}
}
}
After I close an opened connection, the method should print how long it was opened for, or the stopwatch duration. The same problem happened with my CurrentConnection variable, so I put it as a private variable in each class. But isn't the point of having a parent class like this to have common properties that its children classes can interact with?
Problem
I see that in oracle you have:
this.Timeout = OracleStoppy.Elapsed;
Console.WriteLine("Connection closed. \nThe connection was active for {0}", Timeout);
But in sql:
TimeSpan reportedTimeout = Timeout;
Console.WriteLine("Connection closed. \nThe connection was active for {0}", reportedTimeout);
This should be
this.Timeout = SqlStoppy.Elapsed;
Console.WriteLine("Connection closed. \nThe connection was active for {0}", Timeout);
Isn't it?
Advices
You use a parent class, so you don't need two stopwatches, only one is needed else inheritence is useless and you repeat code.
You should consider remove some setters too.
And move CurrentConnection that is repeated, as protected.
This should be:
public abstract class DataBaseConnection
{
protected bool CurrentConnection;
public string ConnectionString { get; }
public TimeSpan Timeout { get; }
public Stopwatch Stoppy { get; }
public abstract void OpenConnection();
public abstract void CloseConnection();
public DataBaseConnection()
{
Timeout = new TimeSpan();
Stoppy = new StopWatch();
}
}
Also use call pattern between constructors:
public OracleConnection()
{
...
}
public OracleConnection(string connectionString)
: this()
{
...
}
You repeat too many same code and you really should refactor and better abstract things.
When code is repeated you can:
create one method and call it instead of repeated code.
sometimes you can move that in a parent class.
When variables is repeated in child classes you can remove them to have only one in a parent class.
You do that playing with modifiers like public, private, protected, internal, abstract, virtual, override...
You should also rename some vars to be more consistent and coherent.
The rule is that a name must be simple and designate exactly what it is.
For example Chrono may be better that Stoppy as well as index or indexRowis better that i.
So here Duration or Elapsed may be better than Timeout that indicates the delay to stop a connection attempt.
Also because classes are named Connection you don't need to specify OpenConnection and CloseConnection: Open and Close is sufficient.
Perhaps you will find this usefull:
How to choose between private and protected access modifier
What is polymorphism
This did not worked when I ran the program!
using MySql.Data;
using MySql.Data.MySqlClient;
namespace MySQL
{
class SqlConnection
{
public SqlConnection() { }
~SqlConnection() { }
private string strConnection = "Server=localhost;Database=database;Port=3306;User ID=root;Password=";
private MySqlConnection connection;
public void OpenConnection()
{
connection = new MySqlConnection();
connection.Open();
}
public void CloseConnection()
{
connection.Close();
connection.Dispose();
}
public string StrConnection
{
set
{
StrConnection = value;
}
get
{
return StrConnection;
}
}
}
}
but it is not working!
ERROR : host 'xxx' is not allowed to connect to this MariaDB sever!
You don't use the connection string property strConnection, when you initialize your connection. Try:
public void OpenConnection()
{
connection = new MySqlConnection(strConnection);
connection.Open();
}
I'm trying to make a thread safe Data Access Layer (kind of like a SQL Data Client wrapper). What are some steps I should be making to make this thread safe, while maximizing performance.
For example, if i add a lock on the sqlConn before it closes the connection (since it implements IDisposable); what if the connection is in the middle of a transaction or query?
In summary, I'm trying to accomplish a thread-safe solution; but at the same time, I do not want to risk any critical exceptions, or any delays. Is there any way I can prioritize the closing thread?
public class SQLWrapper : IDisposable
{
private SqlConnection _sqlConn;
public SQLWrapper(string serverName_, string dbName_)
{
SqlConnectionStringBuilder sqlConnSB = new SqlConnectionStringBuilder()
{
DataSource = serverName_,
InitialCatalog = dbName_,
ConnectTimeout = 30,
IntegratedSecurity = true,
};
sqlConnSB["trusted_connection"] = "yes";
this.start(sqlConnSB.ConnectionString);
}
public SQLWrapper(string connString_)
{
this.start(connString_);
}
private void start(string connString_)
{
if (string.IsNullOrEmpty(connString_) == true)
throw new ArgumentException("Invalid connection string");
**lock (this._sqlConn)**
{
this._sqlConn = new SqlConnection(connString_);
this._sqlConn.Open();
}
}
private void CloseConnection()
{
**lock (this._sqlConn)**
{
this._sqlConn.Close();
this._sqlConn.Dispose();
this._sqlConn = null;
}
}
}
The step you should do is:
NOT making it thread safe.
Simple.
Every thread should have it's own copy, with locking / synchronization happening on the database.
THen it will also scale across computers.
This is the standard approach for the last 20 years or so.
So, every thread creates a new SqlWrapper and everything is fine.
The database performs connection pooling for you; lean on it as much as you can. You really shouldn't require locking.
Option 1.
SqlConnection is not encapsulated by the DAO class; appropriate using structures and storage of the connection string is required at the method level.
public class SomeDAO
{
private readonly string _connectionString;
public SomeDAO(string dsn)
{
_connectionString = dsn;
}
public IEnumerable<AssetVO> DoWork()
{
const string cmdText = "SELECT [AssetId] FROM [dbo].[Asset]";
using (var conn = new SqlConnection(_connectionString))
{
conn.Open();
using (var cmd = new SqlCommand(cmdText, conn))
using (var dr = cmd.ExecuteReader())
{
while (dr.Read())
{
yield return new AssetVO
{
AssetId = Guid.Parse(dr["AssetId"].ToString()),
};
}
}
}
}
}
Option 2.
The SqlConnection is a class member; it's state is carefully maintained by helper methods. Using syntax is used for SqlDataReader and SqlCommand.
public class SomeDAO : IDisposable
{
#region backing store
private readonly SqlConnection _connection;
#endregion
public SomeDAO(string dsn)
{
_connection = new SqlConnection(dsn);
}
public SqlConnection OpenConnection()
{
if (_connection.State != ConnectionState.Closed)
_connection.Open();
return _connection;
}
public void CloseConnection()
{
if (_connection.State != ConnectionState.Closed)
_connection.Close();
}
public IEnumerable<AssetVO> DoWork()
{
const string cmdText = "SELECT [AssetId] FROM [dbo].[Asset]";
try
{
using (var cmd = new SqlCommand(cmdText, OpenConnection()))
using (var dr = cmd.ExecuteReader())
{
while (dr.Read())
{
yield return new AssetVO
{
AssetId = Guid.Parse(dr["AssetId"].ToString()),
};
}
}
}
finally
{
CloseConnection();
}
}
#region Implementation of IDisposable
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public void Dispose()
{
_connection.Dispose();
}
#endregion
}
Both solutions survive a threaded test without the need for explicit locking.
private static volatile bool _done;
private static void Main()
{
#region keyboard interrupt
ThreadPool.QueueUserWorkItem(delegate
{
while (!_done)
{
if (!Console.KeyAvailable) continue;
switch (Console.ReadKey(true).Key)
{
case ConsoleKey.Escape:
_done = true;
break;
}
}
});
#endregion
#region start 3 threads in the pool
ThreadPool.QueueUserWorkItem(DatabaseWorkerCallback);
ThreadPool.QueueUserWorkItem(DatabaseWorkerCallback);
ThreadPool.QueueUserWorkItem(DatabaseWorkerCallback);
#endregion
Thread.Sleep(Timeout.Infinite);
}
private static void DatabaseWorkerCallback(object state)
{
Console.WriteLine("[{0}] Starting", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000);
while (!_done)
{
using (var dao = new SomeDAO(Properties.Settings.Default.DSN))
{
foreach (var assetVo in dao.DoWork())
Console.WriteLine(assetVo);
}
}
Console.WriteLine("[{0}] Stopping", Thread.CurrentThread.ManagedThreadId);
}
I am new to C# and I started studying just yesterday.
I have created class to connect to SQL Server:
namespace Exchange_Ofiice.Classes
{
public class sqlConn
{
public void connectionMethod()
{
SqlConnection myConnection = new SqlConnection("user id=ID;password=PASS;server=SERVER;database=DB;");
try
{
myConnection.Open();
}
catch
{
MessageBox.Show("Невозможно подключиться к Базе данных. Пожалуйста обратитесь к программистам!", "Ошибка подключения к Базе данных", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
myConnection.Close();
}
}
}
}
and another class for user authentification:
namespace Exchange_Ofiice.Classes
{
public class auth:sqlConn
{
public void authMethod()
{
SqlCommand myCommand = new SqlCommand("Command String", myConnection);
}
}
}
How to get (use) SQL connection result (myConnection) in second class?
P.S. line SqlCommand myCommand = new SqlCommand("Command String", myConnection); does not work.
P.S.S. Sorry, if I have mistake, my english is not perfect.
Try this. So you have the SQLConnection in the class and not in the function.
If you declare something in a function it will only be accessible in that function.
public class sqlConn
{
public SqlConnection myConnection;
public void connectionMethod()
{
myConnection = new SqlConnection("user id=ID;password=PASS;server=SERVER;database=DB;");
try
{
myConnection.Open();
}
catch
{
MessageBox.Show("Невозможно подключиться к Базе данных. Пожалуйста обратитесь к программистам!", "Ошибка подключения к Базе данных", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
myConnection.Close();
}
}
}
Oh you might want to consider making the SQLConnection private
private SqlConnection myConnection;
And then make a function to retrieve the value.
public SqlConnection GetConnection()
{
return myConnection;
}
And in the other class it will be:
SqlCommand myCommand = new SqlCommand("Command String", GetConnection());
First of all, connection should be public field of your class, not function variable. And secondly, you're closing your connection in finally, so you have no chance to make it working later.
public class sqlConn
{
public SqlConnection myConnection = new SqlConnection("user id=ID;password=PASS;server=SERVER;database=DB;");
public void connectionMethod()
{
try
{
myConnection.Open();
}
catch
{
//Here goes error handling...
}
}
}
And, surely, in your authMethod you should make checks for connection state, to prevent exceptions, if connection was not initialized.
Also, as good practice, make sure you're implementing IDisposable interface (http://msdn.microsoft.com/en-us/library/system.idisposable.aspx) for your connection class, otherwise you might have some troubles later.
I have the code below to allow me to add data from a excel sheet directly into a sing given database, now I would like to know how I would be able to call the method multiple times to add data from two different excel file at once, the is a button which calls this method once clicked, using multi-threading.
private void AddToDatabase()
{
using (OleDbConnection connection =
new OleDbConnection(excelConnectionString))
{
connection.Open();
CheckNumeberOfSheets(connection);
}
}
Button code;
private void button1_Click(object sender, EventArgs e)
{
AddToDatabase();
}
May be you can pass a string to your method AddToDatabse like
private void AddToDatabase(string fileName){
if(fileName.Equals("yourfirstFile"))
{
using (OleDbConnection connection =
new OleDbConnection(excelConnectionString))
{
connection.Open();
CheckNumeberOfSheets(connection);
}
}
else if(fileName.Equals("yoursecondfile"))
{
using (OleDbConnection connection =
new OleDbConnection(excelConnectionString2))
{
connection.Open();
CheckNumeberOfSheets(connection);
}
}
}
and then call it like this
private void button1_Click(object sender, EventArgs e)
{
AddToDatabase("yourfirstFile");
AddToDatabase("yoursecondFile");
}
Step 1: create a class named "ClassFiles"
public class ClassFiles
{
private String fileName;
private String excelConnectionString;
public String getFileName()
return fileName;
public void setFileName(String fileName)
{
this.fileName=fileName;
}
public String getExcelConnectionString()
return excelConnectionString;
public void setExcelConnectionString(String excelConnectionString)
{
this.excelConnectionString=excelConnectionString;
}
}
Step 2: In your main class, add the fileName along with excelConnection String like:
public class MainClass{
private void AddFilesToDB(List<ClassFiles>fileDetails){
for(ClassFiles fileDeteil : fileDetails){
using (OleDbConnection connection =
new OleDbConnection(fileDeteil.getExcelConnectionString))
{
connection.Open();
CheckNumeberOfSheets(connection);
}
// as well as u can get the file name..
String fileName=fileDeteil.getFileName();
}
}
public Static void main(string args[]){
List<ClassFiles> addDetails =new ArrayList<ClassFiles>();
//now add the no of files into the list
ClassFiles objFile1=new ClassFiles();
objFile1.setFileName("filename1");
objFile1.setExcelConnectionString("excelConnectionString1");
addDetails.add(objFile1);
ClassFiles objFile2=new ClassFiles();
objFile2.setFileName("filename2");
objFile2.setExcelConnectionString("excelConnectionString2");
addDetails.add(objFile2);
and so on..
then call the function for further process.,
new MainClass().AddFilesToDB(addDetails);
}
hope it ll help you..