Refactoring to use a generic function with different input objects - c#

I'd like to refactor some code that runs in a console app. The App updates an external database, and it was recently updated to support either MySQL or SQL Server. So now there are two nearly identical methods with a lot of duplicate code in them, because one has a method signature that uses MySqlConnection and MySqlCommand (etc) and the other uses SqlConnection and SqlCommand (etc).
The code is essentially identical, other than the obvious differences in the ADO objects.
What I'd like to do is something like the following. I've seen several posts here on SO (for e.g. How do I use reflection to call a generic method? ) as well as other sites that show how to set this up with a dynamic type, which is great, except that none of the examples do anything more than write foo.GetType() in the generic method to prove that the dynamic type is correct.
So, how do you call a method on that dynamic type? Of course, when I tried to set this up, trying to call the Open() method on the sqlConnection parameter doesn't compile.
Here's sort of what I'm trying to accomplish:
private static void TransferXmlData(ExportManifest m_settings, XmlNodeList xmlNodeList)
{
if (m_Settings.ServerType.ToLower() == "mysql")
{
using (MySqlConnection mySqlConnection = new MySqlConnection(m_Settings.TargetData.ConnectionString))
{
MySqlCommand mySqlCommand =
new MySqlCommand(Program.GetCommandTextTemplate(m_settings), mySqlConnection);
PrepareSqlCommand(mySqlConnection, mySqlCommand, m_settings)
}
}
else
{
using (SqlConnection sqlConnection =
new SqlConnection(m_Settings.TargetData.ConnectionString))
{
SqlCommand sqlCommand =
new SqlCommand(Program.GetCommandTextTemplate(m_settings), sqlConnection);
PrepareSqlCommand(sqlConnection, sqlCommand, m_settings)
}
}
}
private static void PrepareSqlCommand<T>(T sqlConnection, T sqlCommand, ExportManifest m_settings)
{
// Potentially a lot of code here that looks just like the
// code in the else block, Except that it uses the
// MySqlConnection objects instead of SqlConnection
// Do some stuff
sqlConnection.Open(); // obviously doesn't work
}
Thanks in advance!

May be you can Implement factory design pattern(If you do not want to go with generics, this is my opinion you can think about it.)
This will help you to prevent code duplication.
Implement your Factory class.
`
Public class Factory
{
public static IDbConnection createDbInstance(ExportManifest m_settings)
{
if (m_Settings.ServerType.ToLower() == "mysql")
{
return new MySqlConnection();
}
else
return new SqlConnection();
}
} `
and in your actual method you can use IDbConnection and IDbCommand
private static void TransferXmlData(ExportManifest m_settings, XmlNodeList xmlNodeList)
{
IDbConnection db = Factory.createDbInstance(m_settings);
db.ConnectionString = m_Settings.TargetData.ConnectionString;
IDbCommand comnd = db.CreateCommand();
comnd.CommandText = Program.GetCommandTextTemplate(m_settings);
comnd.CommandType = CommandType.Text;
// db.Open(); if you want to open connection here
PrepareSqlCommand(db, comnd, m_settings);
}
private static void PrepareSqlCommand(IDbConnection sqlConnection, IDbCommand sqlCommand, ExportManifest m_settings)
{
// Potentially a lot of code here that looks just like the
// code in the else block, Except that it uses the
// MySqlConnection objects instead of SqlConnection
// Do some stuff
sqlConnection.Open();
}

In order to write your data access code once, but be able to switch out your implementation based on some logic, you should be coding against IDbConnection.
Something to the effect of:
using (IDbConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["AdventureWorks"].ConnectionString))
{
//execute database actions against IDBConnection
}
In my opinion, this is very well established using the repository pattern, and it shields you from database implementation details, but proper implementation of the pattern might over-complicate your use case. As far as logic to decide which connections get new(), a factory approach as stated above is sufficient, but you could just as easily pass an enum flag if this is a trivial app. In large scale software, you'd typically want to use an Inversion of Control container to control a specifc instance of IDbConnection to get injected in. In any case, reflection, generics, and dynamics would be the wrong tools here (barring any object mapping).

As #Sehnsucht said, you could do something like that:
private static void TransferXmlData(ExportManifest m_settings, XmlNodeList xmlNodeList)
{
if (m_Settings.ServerType.ToLower() == "mysql")
Connect(connectionString => new MySqlConnection(connectionString),
(text, connection) => new MySqlCommand(text, connection));
else
Connect(connectionString => new SqlConnection(connectionString),
(text, connection) => new SqlCommand(text, connection));
}
private static void Connect(ExportManifest m_settings,
Func<string, IDbConnection> createConnection,
Func<string, IDbConnection, IDbCommand> createCommand)
{
using (IDbConnection mySqlConnection =
createConnection(m_Settings.TargetData.ConnectionString))
{
IDbCommand mySqlCommand =
createCommand(Program.GetCommandTextTemplate(m_settings), mySqlConnection);
PrepareSqlCommand(mySqlConnection, mySqlCommand, m_settings);
}
}
private static void PrepareSqlCommand(IDbConnection sqlConnection,
IDbCommand sqlCommand, ExportManifest m_settings)
{
sqlConnection.Open();
}
Both SqlConnection and MySqlConnection inherit from DbConnection which implements IDbConnection. Same go for SqlCommand and MySqlCommand, they implement IDbCommand.
Then, you can use the interfaces to merge your code.
But if, for some reasons, you will need to work with the real types (as return values). You can change your methods for something like this:
private static void Connect<TConnection, TCommand>(ExportManifest m_settings,
Func<string, TConnection> createConnection,
Func<string, TConnection, TCommand> createCommand)
where TConnection : IDbConnection
where TCommand : IDbCommand
{
using (TConnection mySqlConnection =
createConnection(m_Settings.TargetData.ConnectionString))
{
TCommand mySqlCommand =
createCommand(Program.GetCommandTextTemplate(m_settings), mySqlConnection);
PrepareSqlCommand(mySqlConnection, mySqlCommand, m_settings);
}
}
private static void PrepareSqlCommand<TConnection, TCommand>(TConnection sqlConnection,
TCommand sqlCommand, ExportManifest m_settings)
where TConnection : IDbConnection
where TCommand : IDbCommand
{
sqlConnection.Open();
}

Related

Is snowflake net connector thread safe?

Regarding the snowflake .NET connector: https://github.com/snowflakedb/snowflake-connector-net, I can find nothing in the documentation or source code to suggest that connection pooling is supported, and because the connection itself is backed by HttpClient, and we know that HttpClient should be reused rather than created/disposed constantly, what's the best way to use the snowflake .NET connector when you'll be making many queries across threads?
Note: I'm not planning on changing any properties of the connection once it's created (schema, database, etc.).
For example:
// application startup registers this provider as a singleton
public class SnowflakeConnectionProvider : IDisposable
{
private IDbConnection _conn;
public SnowflakeConnectionProvider()
{
_conn = new SnowflakeDbConnection();
_conn.ConnectionString = "connectionString";
_conn.Open();
}
public IDbConnection conn { get => _conn; }
public Dispose() => _conn.Close();
}
Now, is it safe for multiple threads to share the one SnowflakeDbConnection like so:
public class Worker
{
public Worker(SnowflakeConnectionProvider provider)
{
IDbConnection conn = provider.conn;
IDbCommand cmd = conn.CreateCommand();
cmd.CommandText = "select * from t";
IDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
Console.WriteLine(reader.GetString(0));
}
}
}
Summary from GitHub: The connector is thread safe.
As long as you do not use any session variables in your snowflake code, you can have multiple threads sharing the same SnowflakeDbConnection. It does not matter if you are reusing threads or if you are creating new threads all the time.
Even if you are constantly creating and disposing connections from multiple different threads, a single HttpClient is created once and then reused and shared by all connections.
https://github.com/snowflakedb/snowflake-connector-net/issues/275

Making a data access class for all programs or individual C#

So the title is a bit vague, but the question is really this: in practice is it best to make a data access class, in this case access to a SQL Server.
Where all the static methods of the class need a connection string and a SQL statement?
Something along these lines:
public static void ExecuteSql(string connStr, string strSqlStatement)
{
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
SqlCommand cmd = new SqlCommand(strSqlStatement, conn);
cmd.ExecuteNonQuery();
conn.Close();
conn.Dispose();
}
And then a method that does something similar except it returns data you queried for.
Or in practice, is it better to create an object for the specific application you are building, and code these items as the objects extensions. So the SQL to run or stored procedure to execute would be wrapped up in that class.
obj.GetSomethingViaQueryThatIsWrittenInTheClassLibrary()
So I guess the first one is more like a service library for accessing and writing data in a SQL Server database. What does one typically do in this situation?
Or could you even use the service library in tandem with the objects library?
There's a ton of, not conflicting, but different opinions on data access and I am really trying to see what is more common a practice.
I disagree with Terry, because:
The connections are pooled, so opening/closing connections is not a problem and you don't want to use a single connection to execute multiple concurrent queries. This is very usefull when having many concurrent threads (for example webservers) but this also applies on a normal application (which might uses Tasks to retrieve data on a separate thread to keep the UI responsive)
So I would create a ConnectionManager class that uses a connection string as constructor parameter, this way the connectionstring wouldn't 'travel' thru your program and is encapsulated in a 'manager' object.
This is a poor example, but I think it work just fine when using ADO.NET
public class ConnectionManager
{
private string _connectionString;
public ConnectionManager(string connectionString)
{
_connectionString = connectionString;
}
public SqlConnection GetConnection()
{
return new SqlConnection(_connectionString);
}
}
Then I would use it something like:
var connectionManager = new ConnectionManager(connectionString);
using(var con = connectionManager.GetConnection())
{
// not all operations require .Open()/.Close()
// multiple queries.
}
using(var con = connectionManager.GetConnection())
{
// not all operations require .Open()/.Close()
// multiple other queries.
}
By using using the connection will be disposed (put back in the pool)
You might even use something like:
public class ConnectionManager
{
private string _connectionString;
public ConnectionManager(string connectionString)
{
_connectionString = connectionString;
}
public void ExecuteNonQuery(string strSqlStatement)
{
using(var connection = new SqlConnection(_connectionString))
using(var command = new SqlCommand(strSqlStatement, connection))
{
connection.Open();
command.ExecuteNonQuery();
}
}
}
Which makes:
var connectionManager = new ConnectionManager(connectionString);
connectionManager.ExecuteNonQuery("SELECT * FROM Whatever");
Tip: You sure need to checkout the SqlParameter to prevent SQL Injection
I wouldn't create, open, and close the connection in an sql execute method like that. Instead, I recommend creating the connection and pass it in to the query method each time a query is needed and when all queries are finished, then close the connection.

Managing and Closing Dynamically created SQL connections in .net

I have a c# windows form application that connects to databases dynamically where each user may connect to different databases.
The current implementation is as follows:
Connection Repository that contains a dynamically populated list of connections (per user).
When a user initiates a request that requires a database connection the respective connection is looked up from the connection repository ,opened , and then used in the user request .
Code Sample from the connection repository
public class RepoItem
{
public string databasename;
public SqlConnection sqlcnn;
}
public class ConnectionRepository
{
private List<RepoItem> connectionrepositroylist;
public SqlConnection getConnection(String dbname)
{
SqlConnection cnn = (from n in connectionrepositroylist
where n.databasename == dbname
select n.sqlcnn).Single;
cnn.Open();
return cnn;
}
}
sorry for any code errors i just improvised a small version of the implementation for demonstration purpose.
I'am not closing connections after a command execution because it may be used by another command simultaneously.
The questions are:
Should i be worried about closing the connections ?
Does connection close automatically if it is idle for a specific period ?
I have a method in mind to implement a timer in the created Connection Repository and check for idle connections through the Executing ConnectionState Enumeration and close them manually.
Any suggestions are welcome .
When i want a specific connection i call the getConnection function in the ConnectionRepository class and pass the database name as a parameter.
PS: I didn't post the complete implemented code because it is quite big and includes the preferences that affect the populating of the connection list.
I would suggest not to return the SQLConnection to the calling method at all.
Instead, create a method that will accept an Action<SqlConnection>, create the connection inside a using block, and execute the action inside that block
This way you know that the connection will always be correctly closed and disposed, while giving the using code the freedom to do whatever it needs:
public class RepoItem
{
public string databasename;
public SqlConnection sqlcnn;
}
public class DatabaseConnector
{
private List<RepoItem> connectionrepositroylist;
private SqlConnection GetConnection(String dbname)
{
return (from n in connectionrepositroylist
where n.databasename == dbname
select n.sqlcnn).SingleOrDefault();
}
public void Execute(String dbname, Action<SqlConnection> action)
{
using (var cnn = GetConnection(dbname))
{
if (cnn != null) // in case dbname is not in the list...
{
cnn.Open();
action(cnn);
}
}
}
}
Then, to execute an sql statement you can do something like this:
public void ExecuteReaderExample(string dbName, string sql)
{
Execute("dbName",
connection =>
{
using (var cmd = new SqlCommand(sql, connection))
{
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// do stuff with data form the database
}
}
}
});
}
Of course, you can also wrap the SqlCommand in a method like this.
I've been working with this approach for quite some time now, and as far as I can tell it's working well. In fact, It's working so well I've published a project on git hub based on this approach.
It saves you a lot of the plumbing when dealing with ado.net, by wrapping the connection, command, reader and adapter much the same way.
Feel free to download it and adapt to your needs.
P.S.
To answer your questions directly:
Should i be worried about closing the connections ?
Yes, you should.
Does connection close automatically if it is idle for a specific period ?
No, it doesn't.
However, implementing a method like I suggested will handle closing and disposing the connection object for you, so you don't need to worry about it.
Update
As Yahfoufi wrote in his comment, this design has a flaw, since multiple commands are using the same instance of SqlConnection, you are risking closing the connection while other commands are running.
However, fixing this design flaw is very easy - instead of holding SqlConnection in RepoItem you can simply hold the connection string:
public class RepoItem
{
public string DatabaseName {get; set;}
public string ConnectionString {get; set;}
}
Then you change the GetConnection method like this:
private SqlConnection GetConnection(String dbname)
{
return new SqlConnection(from n in connectionrepositroylist
where n.databasename == dbname
select n.sqlcnn).SingleOrDefault());
}
Now each Execute method is working on it's own individual instance of SqlConnection so you don't need to worry about closing in the middle of some other command executing.
However, While we are on the subject of refactoring, I would suggest removing the RepoItem class all together and instead of using a List<RepoItem> to hold the connection strings simply use a Dictionary<string, string>, where the database name is the key and the connection string is the value. This way you can only have one connection string per database name, and your GetConnection method is simplified to this:
private Dictionary<string, string> connectionrepositroylist;
private string GetConnectionString(String dbname)
{
return connectionrepositroylist.ContainsKey(dbname) ? connectionrepositroylist[dbname] : "";
}
So, the complete DatabaseConnector class will look like this:
public class DatabaseConnector
{
private Dictionary<string, string> connectionrepositroylist;
private string GetConnectionString(String dbname)
{
return connectionrepositroylist.ContainsKey(dbname) ? connectionrepositroylist[dbname] : "";
}
public void Execute(String dbname, Action<SqlConnection> action)
{
var connectionString = GetConnectionString(dbname);
if(!string.IsNullOrEmpty(connectionString))
{
using (var cnn = new SqlConnection(connectionString))
{
cnn.Open();
action(cnn);
}
}
}
// Of course, You will need a way to populate your dictionary -
// I suggest having a couple of methods like this to add, update and remove items.
public bool AddOrUpdateDataBaseName(string dbname, string connectionString)
{
if(connectionrepositroylist.ContainsKey(dbname))
{
connectionrepositroylist[dbname] = connectionString;
}
else
{
connectionrepositroylist.Add(dbname, connectionString);
}
}
}
The good news is that ADO.Net manages your connection pools dynamically, so there's minimal overhead in you dynamically opening and closing connections in code. There's a good document here if you want to look through the detail.
To answer the specific questions you've raised:
Should i be worried about closing the connections ?
Yes, but not for the reasons you may think. Microsoft encourage you to close your connections, so as to return them to the pool for (re)use elsewhere in your code. Closing the connection doesn't actually close it - it merely returns the underlying connection to the pool. Failure to close your connections properly can lead to delays in them being returned to the pool, thus adversely affecting your applications performance as more connections need to be added to the pool to cope with demand.
Does connection close automatically if it is idle for a specific
period ?
A connection is only returned to the pool when it's Dispose or Finalise methods get called. If you create a connection and drop it into a static container then it will not be returned to the pool at all. As such, your ConnectionRepository may actually be harming performance.
I have a method in mind to implement a timer in the created Connection
Repository and check for idle connections
This is unnecessary - close your connections to allow them to return to the pool. This way they will be available for other threads to use
Personally, I'd suggest that you modify your RepoItem class to store connection strings, rather than connection objects, and let ADO.Net's pooling do all the heavy lifting.
public static class ConnectionRepository
{
private static readonly Dictionary<string, string> Connections = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
public static bool Contains(string key)
{
return Connections.ContainsKey(key);
}
public static void Add(string key, string connectionString)
{
Connections.Add(key, connectionString);
}
public static SqlConnection Get(string key)
{
var con = new SqlConnection(Connections[key]);
con.Open();
return con;
}
}
With this in place, you can query the database as follows:
public static void foo()
{
using (var con = ConnectionRepository.Get("MyConnection"))
using (var cmd = new SqlCommand("SELECT * FROM MyTable", con))
{
var dr = cmd.ExecuteReader();
//...
}
}
Once the query has executed and the connection is no longer required, the using() block calls its Dispose() method and releases the underlying connection back to the pool for re-use.
As #tinudu says, the SqlConnection class reuses existing connections automatically - you don't have to implement that yourself. See SQL Server Connection Pooling.
If you create the SqlConnection object in a using statement, C# will close the connection automatically as required.
Wrapping the whole thing (create connection, open, run query, close connection) in a function is the best idea. You can put the function in a repository base-class, so it is available to all your repositories.
You would need several functions for the different types of SQL query (select, update, stored proc) but you only need to write one of each - they will get reused.
if you worried about so many conditions let say parallel execution as
well so consider reserving connections for app and close all at once
when app is closing.
public class RepoItem
{
public string databasename;
public SqlConnection sqlcnn;
}
public class ConnectionRepository
{
private List<RepoItem> connectionrepositroylist;
public SqlConnection getConnection(String dbname)
{
SqlConnection cnn = (from n in connectionrepositroylist
where n.databasename == dbname
select n.sqlcnn).Single;
if (cnn!= null && cnn.State == cnn.Closed) // Impelement other checks as well
{
cnn.Open();
}
return cnn;
}
}
Implement CloseConnections and call while application closing i.e
Application.ApplicationExit event
public void CloseConnections()
{
foreach (var connection in connectionrepositroylist)
{
try
{
if (connection.State == System.Data.ConnectionState.Open) // check other conditions
{
connection.Close();
}
}
catch (Exception)
{
//logging or special handling
}
}
}
Points to be note
If some query is still executing and user tries to shut down or close the
app can consider following implementations
Wont allow the application shutdown . Callback delegate will help in this
case to ensure that query is returned.
Force stop and close the connection
It is a better Practice to close the sqlconnection manually, Since it can release the connection which can be used for other processes. Also note that you should open the connection as much as late you can and close it early as possible.

Correctly reusing SqlCommand and SqlParameter whilst pooling the connection

I am working on a setup where a scalable WCF Service Component is connected to a single MS SQL Server Database. The RESTful service allows users to save data into the DB as well as get data from it.
Whilst implementing a class handling the database connections / methods, I started struggling with correctly reusing prepared SqlCommands and the connection. I read up on the MSDN about connection pooling as well as how to use SqlCommand and SqlParameter.
My initial version of the class looks like this:
public class SqlRepository : IDisposable
{
private object syncRoot = new object();
private SqlConnection connection;
private SqlCommand saveDataCommand;
private SqlCommand getDataCommand;
public SqlRepository(string connectionString)
{
// establish sql connection
connection = new SqlConnection(connectionString);
connection.Open();
// save data
saveDataCommand = new SqlCommand("INSERT INTO Table (Operation, CustomerId, Data, DataId, CreationDate, ExpirationDate) VALUES (#Operation, #CustomerId, #Data, #DataId, #CreationDate, #ExpirationDate)", connection);
saveDataCommand.Parameters.Add(new SqlParameter("Operation", SqlDbType.NVarChar, 20));
saveDataCommand.Parameters.Add(new SqlParameter("CustomerId", SqlDbType.NVarChar, 50));
saveDataCommand.Parameters.Add(new SqlParameter("Data", SqlDbType.NVarChar, 50));
saveDataCommand.Parameters.Add(new SqlParameter("DataId", SqlDbType.NVarChar, 50));
saveDataCommand.Parameters.Add(new SqlParameter("CreationDate", SqlDbType.DateTime));
saveDataCommand.Parameters.Add(new SqlParameter("ExpirationDate", SqlDbType.DateTime));
saveDataCommand.Prepare();
// get data
getTripCommand = new SqlCommand("SELECT TOP 1 Data FROM Table WHERE CustomerId = #CustomerId AND DataId = #DataId AND ExpirationDate > #ExpirationDate ORDER BY CreationDate DESC", connection);
getTripCommand.Parameters.Add(new SqlParameter("CustomerId", SqlDbType.NVarChar, 50));
getTripCommand.Parameters.Add(new SqlParameter("DataId", SqlDbType.NVarChar, 50));
getTripCommand.Parameters.Add(new SqlParameter("ExpirationDate", SqlDbType.DateTime));
getTripCommand.Prepare();
}
public void SaveData(string customerId, string dataId, string operation, string data, DateTime expirationDate)
{
lock (syncRoot)
{
saveDataCommand.Parameters["Operation"].Value = operation;
saveDataCommand.Parameters["CustomerId"].Value = customerId;
saveDataCommand.Parameters["CreationDate"].Value = DateTime.UtcNow;
saveDataCommand.Parameters["ExpirationDate"].Value = expirationDate;
saveDataCommand.Parameters["Data"].Value = data;
saveDataCommand.Parameters["DataId"].Value = dataId;
saveDataCommand.ExecuteNonQuery();
}
}
public string GetData(string customerId, string dataId)
{
lock (syncRoot)
{
getDataCommand.Parameters["CustomerId"].Value = customerId;
getDataCommand.Parameters["DataId"].Value = dataId;
getDataCommand.Parameters["ExpirationDate"].Value = DateTime.UtcNow;
using (var reader = getDataCommand.ExecuteReader())
{
if (reader.Read())
{
string data = reader.GetFieldValue<string>(0);
return data;
}
else
{
return null;
}
}
}
}
public void Dispose()
{
try
{
if (connection != null)
{
connection.Close();
connection.Dispose();
}
DisposeCommand(saveDataCommand);
DisposeCommand(getDataCommand);
}
catch { }
}
private void DisposeCommand(SqlCommand command)
{
try
{
command.Dispose();
}
catch (Exception)
{
}
}
}
There are several aspects important to know:
I am using SqlCommand.Prepare() to speed up the process of executing the command
Reusing the commands avoids creating new objects with every call to the GetData and SaveData methods, thus leading to no problem with the garbage collector
There is only one instance of the SqlRepository class, used by the WCF Service.
There are many many calls per minute to this service, so keeping a connection to the DB open is what I want.
Now I read up a bit more about connection pooling and the fact that it is highly recommended to use the SqlConnection object in a using statement to ensure disposal. To my understanding, the connection pooling technology takes care of leaving the connection open even though the Dispose() method of SqlConnection has been called by the using statement.
The way to use this would be to have a using(SqlConnection connection = new SqlConnection(connectionString)) inside the GetData and SaveData methods. However, then - at least to my intuition - I would need to create the SqlCommands inside the GetData / SaveData methods as well. Or not? I could not find any documentation on how to reuse the commands that way. Also wouldn't the call to SqlCommand.Prepare() be meaningless if I need to prepare a new command every time I get into the GetData / SaveData methods?
How do I properly implement the SqlRepository class? The way it is now I believe that if the connection breaks (maybe because the DB server goes down for a while and reboots), then the SqlRepository class will not automatically recover and be functioning. To my best knowledge this sort of failsave scenarios are handled in the pooling technology.
Thanks for ideas and feedback!
Christian
Do not reuse the SqlCommand instances.
You are synchronizing database access.
With your implementation, you are re-using a small object (which is no problem for the GC even if there are thousands) in exchange of concurrent DB operations.
Remove the synchronization locks.
Create new instances of SqlCommands for each database operation.
Do not call Prepare. Prepare speeds up db operations, but after executing ExecuteReader() on a SqlCommand with CommandType = Text and with non-zero number of parameters, the command is unprepared internally.

C#.net lock object in one mthod and no lock in another method

I have two method “ExecuteNoQuery” (performs dbCommand.ExecuteNonQuery()) and “Query” performs (dbCommand.ExecuteReader()).
Both the methods are using same connection object. In ExecuteNoQuery method a lock is implemented(using connection object) and Query method implemented with out lock. In case of multiple thred, different thread accessing both the method simultaneously then what will happen?
Note: In Query method custom connection pooling is implemented with the same object.
public int ExecuteNoQuery(string sqlquery, Hashtable htData) {
try {
lock(Myservice.dbcon)
{
using (OracleCommand dbCommand = new OracleCommand(sqlquery, Myservice.dbcon))
{
int rowCount = dbCommand.ExecuteNonQuery();
return 1;
}
}
}
public OracleDataReader Query(string sqlquery, Hashtable htData)
{
try
{
OracleDataReader dbReader = null;
Random ran = new Random();
int randomnumber = ran.Next(1,5);
Myservice.dbcon = (OracleConnection) Myservice.htdbcon
["Connection_" +randomnumber];
if (Myservice.dbcon.State != System.Data.ConnectionState.Executing
|| Myservice.dbcon != System.Data.ConnectionState.Fetching)
{
using (OracleCommand dbCommand = new OracleCommand(sqlquery,
Myservice.dbcon))
{
dbReader = dbCommand.ExecuteReader();
}
}
return dbReader;
}
Both the methods are using same connection object.
Since one method uses a lock and the other does not: bad things. No guarantees are made by the object for this scenario, so you should expect it to fail in interesting ways. You should use the same lock object from both places, or better: only use a connection in isolated code, not a shared connection. With connection pooling, it is very rarely useful to have a shared connection object somewhere. A far more suitable pattern is usually to obtain a connection when you need it, and then dispose it. If the underlying provider supports pooling, this will perform ideally, without any issues of synchronization, and will allow parallel queries etc. For example:
using (var conn = SomeUtilityClass.GetOpenConnection())
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = sqlquery;
int rowCount = dbCommand.ExecuteNonQuery();
return 1;
}
and, importantly, do the same from the Query method; no locks, no global shared connections.
I'd also be concerned by the lack of parameters, btw. That suggests you are opening yourself up to SQL injection errors.

Categories

Resources