I have this issue in production with MySQL connections where the connection is either being used or it's not opened error comes up frequently. I think when multiple requests hit the method then this issue is happening. I got stats from production were 80 different instances hit the Graphql method. I am using Sqlkata to make DB calls. When there are no parallel calls then it works fine.
ConnectionManager.cs
public IDbConnection GetConnection
{
get
{
if (_iDbConnection != null)
{
if (_iDbConnection.State != ConnectionState.Open)
{
_iDbConnection.Open();
return _iDbConnection;
}
}
if (_iDbConnection != null && _iDbConnection.State == ConnectionState.Open)
{
// close the previous connection
_iDbConnection.Close();
// open new connection
_iDbConnection.Open();
return _iDbConnection;
}
try
{
string connectionString = Configuration.GetConnectionString("seasonal");
// Register the factory
DbProviderFactories.RegisterFactory("MySqlConnector", MySqlConnectorFactory.Instance);
// Get the provider invariant names
IEnumerable<string> invariants = DbProviderFactories.GetProviderInvariantNames();
var factory = DbProviderFactories.GetFactory(invariants.FirstOrDefault());
var conn = factory.CreateConnection();
if (conn != null)
{
conn.ConnectionString = connectionString;
conn.Open();
_iDbConnection = conn;
}
}
catch (Exception e)
{
throw;
}
return _iDbConnection;
}
}
Service (constructor)
public OutboundRecordService(IConnectionManager connectionManager) : base(connectionManager)
{
IDbConnection connection = connectionManager.GetConnection;
if (connection.State != ConnectionState.Open)
{
_logger.Error($"Connection is not open, current state: {connection.State}");
}
_queryFactory = new QueryFactory(connection, new MySqlCompiler());
_logger = LogManager.GetLogger(typeof(OutboundRecordService<T>));
}
public async Task<CareMetx.Service.Models.PaginationResult<OutboundRecord>> GetAllByCriteria(OutboundRecordSearchCriteria searchCriteria)
{
try
{
// START - Test code
var arrayTask = new List<Task>();
int i = 10;
for (int c = 0; c < i; c++)
{
arrayTask.Add(Task.Factory.StartNew(() => GetDataFromDB(searchCriteria)));
}
Task.WaitAll(arrayTask.ToArray());
Console.WriteLine("All threads complete");
return await Task.FromResult<CareMetx.Service.Models.PaginationResult<OutboundRecord>>(null);
// END - Test code
}
catch (Exception ex)
{
var message = ex.Message;
}
return null;
}
private async Task<List<OutboundRecord>> GetDataFromDB(OutboundRecordSearchCriteria searchCriteria)
{
Query dbQuery = _queryFactory.Query("SELECT * FROM OutboundRecords Where BatchId = 1");
// Clone the query and get the total count
var totalCountQuery = dbQuery.Clone();
totalCountQuery = totalCountQuery.AsCount();
// Log Record Count SQL
LogSqlQuery(totalCountQuery);
// Get the total record count
var totalRecords = await totalCountQuery.FirstOrDefaultAsync<int>();
}
Exception
How to find whether the user is connecting to the internet using wired?
Here are my current progress
var internetConnectionProfile = Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile();
if (internetConnectionProfile.GetNetworkConnectivityLevel() == Windows.Networking.Connectivity.NetworkConnectivityLevel.InternetAccess)
{
// has internet connection
}
if (internetConnectionProfile.IsWwanConnectionProfile)
{
// its mobile
}
if (internetConnectionProfile.IsWlanConnectionProfile)
{
// its wireless
}
Try this
bool IsWiredInternetAccess()
{
IReadOnlyList<ConnectionProfile> connections = NetworkInformation.GetConnectionProfiles();
foreach (var connection in connections)
{
if (connection == null) continue;
if (connection.GetNetworkConnectivityLevel() == NetworkConnectivityLevel.InternetAccess)
{
// check is connection wired
if ((connection.ConnectionProfile.IsWlanConnectionProfile)||(connection.IsWwanConnectionProfile))
{
// connection is Wlan or Wwan
return false;
}
else
{
return true;
}
}
}
}
Here is a simple and updated answer
Updated ConnectionProfile class helps to identify ,type of network connection.
ConnectionProfile connectionProfile = NetworkInformation.GetInternetConnectionProfile();
bool isWifi = connectionProfile.IsWlanConnectionProfile;
How to check internet connection availability in Windows 8,C# development ? I looked at MSDN but page has been deleted.
I use this snippet without problems:
public static bool IsInternet()
{
ConnectionProfile connections = NetworkInformation.GetInternetConnectionProfile();
bool internet = connections != null && connections.GetNetworkConnectivityLevel() == NetworkConnectivityLevel.InternetAccess;
return internet;
}
I had to use GetConnectionProfiles() and GetInternetConnectionProfile() to make it work across all devices.
class ConnectivityUtil
{
internal static bool HasInternetConnection()
{
var connections = NetworkInformation.GetConnectionProfiles().ToList();
connections.Add(NetworkInformation.GetInternetConnectionProfile());
foreach (var connection in connections)
{
if (connection == null)
continue;
if (connection.GetNetworkConnectivityLevel() == NetworkConnectivityLevel.InternetAccess)
return true;
}
return false;
}
}
For Windows Phone Following code may be usefull:
var networkInformation = NetworkInformation.GetConnectionProfiles();
if (networkInformation.Count == 0)
{
//no network connection
}
I created a method while back that:
Locked a table
Read value from it
Wrote updated value back
Unlocked the table
The code worked for Oracle. Now I can't get it work for SQL Server 2008. The method is below and executing my unlocking command results in a SqlException with text:
"NOLOC" is not a recognized table hints option. If it is intended as a
parameter to a table-valued function or to the CHANGETABLE function,
ensure that your database compatibility mode is set to 90.
Code:
public static int GetAndSetMaxIdTable(DbProviderFactory factory, DbConnection cnctn, DbTransaction txn, int tableId, string userName, int numberOfIds)
{
bool isLocked = false;
string sql = string.Empty;
string maxIdTableName;
if (tableId == 0)
maxIdTableName = "IdMax";
else
maxIdTableName = "IdMaxTable";
try
{
bool noPrevRow = false;
int realMaxId;
if (factory is OracleClientFactory)
sql = string.Format("lock table {0} in exclusive mode", maxIdTableName);
else if (factory is SqlClientFactory)
sql = string.Format("select * from {0} with (TABLOCKX)", maxIdTableName);
else
throw new Exception(string.Format("Unsupported DbProviderFactory -type: {0}", factory.GetType().ToString()));
using (DbCommand lockCmd = cnctn.CreateCommand())
{
lockCmd.CommandText = sql;
lockCmd.Transaction = txn;
lockCmd.ExecuteNonQuery();
isLocked = true;
}
using (DbCommand getCmd = cnctn.CreateCommand())
{
getCmd.CommandText = CreateSelectCommand(factory, tableId, userName, getCmd, txn);
object o = getCmd.ExecuteScalar();
if (o == null)
{
noPrevRow = true;
realMaxId = 0;
}
else
{
realMaxId = Convert.ToInt32(o);
}
}
using (DbCommand setCmd = cnctn.CreateCommand())
{
if (noPrevRow)
setCmd.CommandText = CreateInsertCommand(factory, tableId, userName, numberOfIds, realMaxId, setCmd, txn);
else
setCmd.CommandText = CreateUpdateCommand(factory, tableId, userName, numberOfIds, realMaxId, setCmd, txn);
setCmd.ExecuteNonQuery();
}
if (factory is OracleClientFactory)
sql = string.Format("lock table {0} in share mode", maxIdTableName);
else if (factory is SqlClientFactory)
sql = string.Format("select * from {0} with (NOLOC)", maxIdTableName);
using (DbCommand lockCmd = cnctn.CreateCommand())
{
lockCmd.CommandText = sql;
lockCmd.Transaction = txn;
lockCmd.ExecuteNonQuery();
isLocked = false;
}
return realMaxId;
}
catch (Exception e)
{
...
}
}
So what goes wrong here? Where does this error come from? Server or client? I copied the statement from C code and it's supposed to work there. Unfortunately I can't debug and check if it works for me.
Edit: Just trying to lock and unlock (without reading or updating) results in same exception.
Thanks & BR -Matti
The TABLOCKX hint locks the table as you intend, but you can't unlock it manually. How long the lock stays on depends on your transaction level. If you don't have an active transaction on your connection, the lock is held while the SELECT executes and is discarded thereafter.
If you want to realize the sequence "lock the table -> do something with the table -> release the lock" you would need to implement the ADO.NET equivalent of this T-SQL script:
BEGIN TRAN
SELECT TOP (1) 1 FROM myTable (TABLOCKX, KEEPLOCK)
-- do something with the table
COMMIT -- This will release the lock, if there is no outer transaction present
you can either execute the "BEGIN TRAN"/"COMMIT" through DbCommand objects or you can use the System.Data.SqlClient.SqlTransaction class to start a transaction and commit it.
Attention: This approach only works if your connection is not enlisted in a transaction already! SQL Server doesn't support nested transaction, so the COMMIT wouldn't do anything and the lock would be held. If you have a transaction already running, you cannot release the lock until the transaction finishes. In this case maybe a synchronisation through sp_getapplock/sp_releaseapplock might help.
Edit: If you want to educate yourself about transactions, locking and blocking, I recommend these two videos: http://technet.microsoft.com/en-us/sqlserver/gg545007.aspx and http://technet.microsoft.com/en-us/sqlserver/gg508892.aspx
Here is answer for one table for SqlClient with code I made based on TToni's answer:
public static int GetAndSetMaxIdTable(DbProviderFactory factory, DbConnection cnctn, DbTransaction txn, int numberOfIds)
{
bool noPrevRow = false;
int realMaxId;
using (DbCommand getCmd = cnctn.CreateCommand())
{
getCmd.CommandText = "SELECT MaxId FROM IdMax WITH (TABLOCKX)"
getCmd.Transaction = txn;
object o = getCmd.ExecuteScalar();
if (o == null)
{
noPrevRow = true;
realMaxId = 0;
}
else
{
realMaxId = Convert.ToInt32(o);
}
}
using (DbCommand setCmd = cnctn.CreateCommand())
{
if (noPrevRow)
setCmd.CommandText = CreateInsertCommand(factory, tableId, userName, numberOfIds, realMaxId, setCmd, txn);
else
setCmd.CommandText = CreateUpdateCommand(factory, tableId, userName, numberOfIds, realMaxId, setCmd, txn);
setCmd.ExecuteNonQuery();
}
return realMaxId;
}
and it i's like this:
...
try
{
using (txn = cnctn.BeginTransaction())
{
oldMaxId = GetAndSetMaxIdTable(factory, cnctn, txn, 5);
for (i = 0; i < 5; i++)
{
UseNewIdToInsertStuff(factory, cnctn, txn, oldMaxId + i + 1)
}
txn.Commit();
return true;
}
}
catch (Exception e)
{
// don't know if this is needed
if (txn != null && cnctn.State == ConnectionState.Open)
txn.Rollback();
throw e;
}
...
For oracle client it seems to be desirable to have:
SELECT MaxId from IdMax WHERE ... FOR UPDATE OF MaxId
-m
I want to increase the time to retrieve data from my tableadapter. How do i set it? I tried using this:
http://www.codeproject.com/KB/database/TableAdaptrCommandTimeout.aspx
However, the _commandCollection.Length is set to null therefore i am unable to set the CommandTimeout
Any ideas?
You have to call the GetData() Method on your tableAdapter before you can set the timeout, othewise the SelectCommand will not have been initialized.
protected void setAdapterTimeout(SqlDataAdapter da, int timeOut = 120)
{
if (da.SelectCommand != null)
da.SelectCommand.CommandTimeout = timeOut;
}
Then call it like this:
//Replacing AccessoryTableAdapter with your table Adapter
AccessoryTableAdapter ata = new AccessoryTableAdapter();
setAdapterTimeout(ata.Adapter);
EDIT: Extension Methods are cool!
public static class Extensions
{
public static void setAdapterTimeout(this SqlDataAdapter da, int timeOut = 120)
{
if (da.SelectCommand != null)
da.SelectCommand.CommandTimeout = timeOut;
if (da.InsertCommand != null)
da.InsertCommand.CommandTimeout = timeOut;
}
}
then call it:
AccessoryTableAdapter ata = new AccessoryTableAdapter();
ata.Adapter.setAdapterTimeout(120);
In my case this work correctly.
The only think is adding this row of code at the original codeproject solution:
if ((this._commandCollection == null)) this.InitCommandCollection();
So, the SelectCommandTimeout propery become:
// Add this check before the assign step...
if ((this._commandCollection == null)) this.InitCommandCollection();
for (int i = 0; i < this._commandCollection.Length; i++)
{
if ((this._commandCollection[i] != null))
{
((System.Data.SqlClient.SqlCommand)
(this._commandCollection[i])).CommandTimeout = value;
}
}
}
}