I have written this class to automate SQLDependencys
public class DatabaseChangeAlert
{
private String connectionString;
private SqlConnection sc;
public event EventHandler<DatabaseChangedEvent> DatabaseChangeEvent;
private String tabelle;
private String query;
public DatabaseChangeAlert(String tabelle, String conString)
{
try
{
this.tabelle = tabelle;
this.sc = new SqlConnection(conString); ;//new SqlConnection(GlobalResources.ConnectionString);
this.connectionString = conString;
String sel = "";
using (SqlConnection con = new SqlConnection(conString))
{
con.Open();
SqlCommand cmd = con.CreateCommand();
cmd.CommandText = "SELECT dbo.syscolumns.name AS Spaltenname " +
" FROM dbo.syscolumns INNER JOIN " +
" dbo.sysobjects ON dbo.syscolumns.id = dbo.sysobjects.id " +
" WHERE (dbo.sysobjects.xtype = 'U') and dbo.sysobjects.name='" + tabelle + "' ";
using (SqlDataReader sr = cmd.ExecuteReader())
{
while (sr.Read())
{
sel += "["+sr.GetString(0)+"],";
}
}
sel = sel.Substring(0, sel.Length - 1);
}
query = "SELECT " + sel + " from [dbo].[" + tabelle+"]";
}
catch (Exception ex) { }
}
~DatabaseChangeAlert()
{
if(connectionString!=null)
SqlDependency.Stop(connectionString);
}
public void start()
{
try
{
SqlDependency.Start(connectionString);
}
catch (Exception ex)
{
// log(ex)
}
try
{
startDependency();
}
catch (Exception ex)
{
// log(ex)
}
}
private void startDependency()
{
// Assume connection is an open SqlConnection.
// Create a new SqlCommand object.
using (SqlCommand command = new SqlCommand(query, sc))
{
sc.Open();
// Create a dependency and associate it with the SqlCommand.
SqlDependency dependency = new SqlDependency(command);
// Maintain the refence in a class member.
// Subscribe to the SqlDependency event.
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
// Execute the command.
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
}
}
sc.Close();
}
}
void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Info != SqlNotificationInfo.Invalid)
{
startDependency();
if (DatabaseChangeEvent != null)
{
DatabaseChangeEvent(this, new DatabaseChangedEvent(tabelle,e.Info));
}
}
}
public class DatabaseChangedEvent : EventArgs
{
public readonly String Tablename;
public readonly SqlNotificationInfo info;
public DatabaseChangedEvent(String tablename,SqlNotificationInfo info)
{
this.Tablename = tablename;
this.info = info;
}
}
}
in my program I use this Class like that:
DatabaseChangeAlert alerttz = new DatabaseChangeAlert("table1", GlobalResources.ConnectionString);
alerttz.DatabaseChangeEvent += (e,d)=>{
MessageBox.Show("table1 changed");
};
alerttz.start();
DatabaseChangeAlert alert = new DatabaseChangeAlert("table2", GlobalResources.ConnectionString);
alert.DatabaseChangeEvent += (e, d) =>
{
MessageBox.Show("table2 changed");
};
alert.start();
Now my Problem is that when I change anything in table2 I do not get a notification, but when I do the same for table 1 I get a notification!
any ideas what the problem could be?
I also tried to only suscribe for table2...but it remain the same.
I've repeated your situation and wrote unit test (TwoTablesNotificationTest), but didn't find anything. It works fine for me. In this situation you could stop receive notifications from SqlDependency in case of destructor call of some DatabaseChangeAlert entity, because it has SqlDependency.Stop(connectionString) instruction. Thus, you have to call SqlDependency.Start after every SqlDependency.Stop to continue receiving events, but destructor is called automatically by garbage collector from parallel thread and it may cause this effect.
And I want to warn you - be careful using SqlDependency class because it has memory leak problem. For my project I used open source realization of SqlDependency - SqlDependencyEx. It is very easy to use:
int changesReceived = 0;
using (SqlDependencyEx sqlDependency = new SqlDependencyEx(
TEST_CONNECTION_STRING, TEST_DATABASE_NAME, TEST_TABLE_NAME))
{
sqlDependency.TableChanged += (o, e) => changesReceived++;
sqlDependency.Start();
// Make table changes.
MakeTableInsertDeleteChanges(changesCount);
// Wait a little bit to receive all changes.
Thread.Sleep(1000);
}
Assert.AreEqual(changesCount, changesReceived);
Hope this helps.
Related
I insert unique data into SQL Server, but it is inserted twice. It happens one or twice time a year. When I delete inserted data and run procedure again, it doesn't happen on same data again. What is the reason and how to avoid it?
I use a SQL Server stored procedure, where is many select, use sequence, insert is in cursor. In procedure there is begin and commit transaction around insert. Duplicate happens for more orders, but after insert data for one order, there is commit. Error happens in one minute and another batch of inserts few minutes later, is OK.
using System;
using System.Diagnostics;
using System.ServiceProcess;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
//using System.
using System.Text;
using System.Timers;
using System.IO;
using System.Configuration;
namespace WindowsService
{
class WindowsService : ServiceBase
{
Timer myTimer;
bool _smyckaBezi;
public WindowsService()
{
this.ServiceName = "Windows Service Jobs OSTRA SAP";
this.EventLog.Log = "Application";
// These Flags set whether or not to handle that specific
// type of event. Set to true if you need it, false otherwise.
this.CanHandlePowerEvent = true;
this.CanHandleSessionChangeEvent = true;
this.CanPauseAndContinue = true;
this.CanShutdown = true;
this.CanStop = true;
}
static void Main()
{
ServiceBase.Run(new WindowsService());
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
myTimer = new Timer(5000); // Sets a 10 second interval
myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed);// Specifies The Event Handler
myTimer.Enabled = true; // Enables the control
myTimer.AutoReset = true; // makes it repeat
myTimer.Start();
}
protected void myTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (_smyckaBezi) return;
_smyckaBezi = true;
SqlConnection conn = null;
string output = null;
List<string> list = new List<string>();
try
{
Config config = new Config();
string cs = ConfigurationManager.ConnectionStrings["connectionStringName"].ConnectionString;
conn = new SqlConnection(cs);
conn.Open();
SqlCommand command = conn.CreateCommand();
command.CommandText = "SELECT TOP 1 procedure_name AS [procedure_name] FROM dbo.jobs_sap WHERE datediff(minute, next_execution, getdate())>=0 AND upper(procedure_name) IN (SELECT upper(s.name)+'.'+upper(o.name) FROM sys.objects o JOIN sys.schemas s ON o.schema_id=s.schema_id WHERE o.type='P') ORDER BY next_execution";
command.CommandType = CommandType.Text;
// execute the command that returns a SqlDataReader
SqlDataReader reader = command.ExecuteReader();
// display the results
while (reader.Read())
{
output = reader["procedure_name"].ToString();
list.Add(output);
}
reader.Close();
for (int i = 0; i < list.Count; i++) // Loop through List with for
{
string pname = list[i];
string sql = "UPDATE dbo.jobs_sap SET last_execution = next_execution WHERE execution_time is not null AND procedure_name= '" + pname + "';";
SqlCommand cmdu = new SqlCommand(sql, conn);
cmdu.ExecuteNonQuery();
sql = "UPDATE dbo.jobs_sap SET next_execution = convert(datetime,CAST(getdate()+1 AS DATE)) + CAST(execution_time AS DATETIME) WHERE execution_time is not null AND procedure_name= '" + pname + "';";
cmdu = new SqlCommand(sql, conn);
cmdu.ExecuteNonQuery();
string sql2 = "UPDATE dbo.jobs_sap SET last_execution = next_execution WHERE execute_every_min is not null AND procedure_name= '" + pname + "';";
SqlCommand cmdu2 = new SqlCommand(sql2, conn);
cmdu2.ExecuteNonQuery();
sql2 = "UPDATE dbo.jobs_sap SET next_execution = dateadd(minute, execute_every_min,getdate()) WHERE execute_every_min is not null AND procedure_name= '" + pname + "';";
cmdu2 = new SqlCommand(sql2, conn);
cmdu2.ExecuteNonQuery();
_smyckaBezi = false;
SqlCommand cmd = new SqlCommand(list[i], conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 0;
cmd.ExecuteNonQuery();
}
}
catch(Exception ex)// catch (InvalidCastException e)
{
writeToLogFileService(ex.ToString());
}
finally
{
if (conn != null)
{
conn.Close();
_smyckaBezi = false;
}
}
}
public static void writeToLogFileService(string logMessage)
{
string str_LogMessage = string.Empty;
string str_LogFile = "d:\\temp\\log_jobs_sap.txt";
StreamWriter swLog;
str_LogMessage = string.Format("{0}: {1}", DateTime.Now, logMessage);
if (!File.Exists(str_LogFile))
{
swLog = new StreamWriter(str_LogFile);
}
else
{
swLog = File.AppendText(str_LogFile);
}
swLog.WriteLine(str_LogMessage);
swLog.WriteLine();
swLog.Close();
}
protected override void OnStop()
{
base.OnStop();
}
protected override void OnPause()
{
base.OnPause();
}
protected override void OnContinue()
{
base.OnContinue();
}
protected override void OnShutdown()
{
base.OnShutdown();
}
protected override void OnCustomCommand(int command)
{
base.OnCustomCommand(command);
}
protected override bool OnPowerEvent(PowerBroadcastStatus powerStatus)
{
return base.OnPowerEvent(powerStatus);
}
protected override void OnSessionChange(
SessionChangeDescription changeDescription)
{
base.OnSessionChange(changeDescription);
}
}
}
using System;
using System.ComponentModel;
using System.Configuration.Install;
using System.ServiceProcess;
namespace WindowsService
{
[RunInstaller(true)]
public class WindowsServiceInstaller : Installer
{
/// <summary>
/// Public Constructor for WindowsServiceInstaller.
/// - Put all of your Initialization code here.
/// </summary>
public WindowsServiceInstaller()
{
ServiceProcessInstaller serviceProcessInstaller =
new ServiceProcessInstaller();
ServiceInstaller serviceInstaller = new ServiceInstaller();
//# Service Account Information
serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
serviceProcessInstaller.Username = null;
serviceProcessInstaller.Password = null;
//# Service Information
serviceInstaller.DisplayName = "Windows Service Jobs OSTRA SAP";
serviceInstaller.StartType = ServiceStartMode.Automatic;
//# This must be identical to the WindowsService.ServiceBase name
//# set in the constructor of WindowsService.cs
serviceInstaller.ServiceName = "Windows Service Jobs OSTRA SAP";
this.Installers.Add(serviceProcessInstaller);
this.Installers.Add(serviceInstaller);
}
}
}
Thanks for comments, it was helpfull. C# service fired procedure twice times. So I added second control directly into service (first check in procedure was not enough). Solution:
using System;
using System.Diagnostics;
using System.ServiceProcess;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
//using System.
using System.Text;
using System.Timers;
using System.IO;
using System.Configuration;
using log4net;
namespace WindowsService
{
class WindowsService : ServiceBase
{
Timer myTimer;
bool _smyckaBezi;
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public WindowsService()
{
this.ServiceName = "Windows Service Jobs";
this.EventLog.Log = "Application";
// These Flags set whether or not to handle that specific
// type of event. Set to true if you need it, false otherwise.
this.CanHandlePowerEvent = true;
this.CanHandleSessionChangeEvent = true;
this.CanPauseAndContinue = true;
this.CanShutdown = true;
this.CanStop = true;
}
static void Main(string[] args)
{
log4net.Config.XmlConfigurator.Configure();
if (args.Length > 0 && args[0] == "/console")
{
WindowsService ws = new WindowsService();
ws.Start();
System.Threading.Thread.Sleep(int.MaxValue);
}
else
{
ServiceBase.Run(new WindowsService());
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
myTimer = new Timer(10000); // Sets a 10 second interval
myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed);// Specifies The Event Handler
myTimer.Enabled = true; // Enables the control
myTimer.AutoReset = true; // makes it repeat
myTimer.Start();
}
public void Start()
{
//base.OnStart(args);
myTimer = new Timer(10000); // Sets a 10 second interval
myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed);// Specifies The Event Handler
myTimer.Enabled = true; // Enables the control
myTimer.AutoReset = true; // makes it repeat
myTimer.Start();
}
protected void myTimer_Elapsed(object sender, ElapsedEventArgs e)
{
using (LogEx le = new LogEx(log))
{
if (_smyckaBezi) return;
_smyckaBezi = true;
SqlConnection conn = null;
string output = null;
List<string> list = new List<string>();
try
{
Config config = new Config();
string cs = ConfigurationManager.ConnectionStrings["connectionStringName"].ConnectionString;
conn = new SqlConnection(cs);
conn.Open();
SqlCommand command = conn.CreateCommand();
command.CommandText = "SELECT TOP 1 procedure_name AS [procedure_name] FROM dbo.jobs_crm WHERE ISNULL(spusteno_WS,0)=0 AND datediff(minute, next_execution, getdate())>=0 AND upper(procedure_name) IN (SELECT upper(s.name)+'.'+upper(o.name) FROM sys.objects o JOIN sys.schemas s ON o.schema_id=s.schema_id WHERE o.type='P') ORDER BY next_execution";
command.CommandType = CommandType.Text;
// execute the command that returns a SqlDataReader
SqlDataReader reader = command.ExecuteReader();
// display the results
while (reader.Read())
{
output = reader["procedure_name"].ToString();
list.Add(output);
}
reader.Close();
for (int i = 0; i < list.Count; i++) // Loop through List with for
{
string pname = list[i];
try
{
string sql = "UPDATE dbo.jobs_crm SET spusteno_WS=1, last_execution = getdate(), next_execution = convert(datetime,CAST(getdate()+1 AS DATE)) + CAST(execution_time AS DATETIME) WHERE execution_time is not null AND procedure_name= '" + pname + "';";
SqlCommand cmdu = new SqlCommand(sql, conn);
cmdu.ExecuteNonQuery();
string sql2 = "UPDATE dbo.jobs_crm SET spusteno_WS=1, last_execution = getdate(), next_execution = dateadd(minute, execute_every_min,getdate()) WHERE execute_every_min is not null AND procedure_name= '" + pname + "';";
SqlCommand cmdu2 = new SqlCommand(sql2, conn);
cmdu2.ExecuteNonQuery();
_smyckaBezi = false;
//execute procedure
SqlCommand cmd = new SqlCommand(list[i], conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 0;
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(pname + " > " + ex.Message + (ex.InnerException != null ? ex.InnerException.Message : ""));
//le.Exception(ex);
le.Error(pname + " > " + ex.Message + (ex.InnerException != null ? ex.InnerException.Message : ""));
}
finally
{
string sql3 = "UPDATE dbo.jobs_crm SET spusteno_WS=0 WHERE procedure_name= '" + pname + "';";
SqlCommand cmdu3 = new SqlCommand(sql3, conn);
cmdu3.ExecuteNonQuery();
}
}
}
catch (Exception ex)// catch (InvalidCastException e)
{
Console.WriteLine(ex.Message + (ex.InnerException != null ? ex.InnerException.Message : ""));
le.Error("Obecná chyba > " + ex.Message + (ex.InnerException != null ? ex.InnerException.Message : ""));
//writeToLogFileService(ex.ToString());
}
finally
{
if (conn != null)
{
conn.Close();
_smyckaBezi = false;
} } } }
public static void writeToLogFileService(string logMessage)
{
string str_LogMessage = string.Empty;
string str_LogFile = "d:\\temp\\log_jobs_test_crm.txt";
StreamWriter swLog;
str_LogMessage = string.Format("{0}: {1}", DateTime.Now, logMessage);
if (!File.Exists(str_LogFile))
{
swLog = new StreamWriter(str_LogFile);
}
else
{
swLog = File.AppendText(str_LogFile);
}
swLog.WriteLine(str_LogMessage);
swLog.WriteLine();
swLog.Close();
}
protected override void OnStop()
{
base.OnStop();
}
protected override void OnPause()
{
base.OnPause();
}
protected override void OnContinue()
{
base.OnContinue();
}
protected override void OnShutdown()
{
base.OnShutdown();
}
protected override void OnCustomCommand(int command)
{
base.OnCustomCommand(command);
}
protected override bool OnPowerEvent(PowerBroadcastStatus powerStatus)
{
return base.OnPowerEvent(powerStatus);
}
protected override void OnSessionChange(
SessionChangeDescription changeDescription)
{
base.OnSessionChange(changeDescription);
}
}
}
I have below code for SqlDependency. Below call back function is get called every time when data reader is executed. Rather than this call back function not get executing when i change some value in Table.
public IEnumerable<Messages> GetAllMessages()
{
var messages = new List<Messages>();
using (var connection = new SqlConnection(_connString))
{
connection.Open();
using (var command = new SqlCommand("SELECT SUM(MessageID) FROM [dbo].[Messages] group by Message", connection))
{
command.Notification = null;
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
while (reader.Read())
{
// messages.Add(item: new Messages { MessageID = (int)reader["MessageID"], Message = (string)reader["Message"], EmptyMessage = reader["EmptyMessage"] != DBNull.Value ? (string)reader["EmptyMessage"] : "", MessageDate = Convert.ToDateTime(reader["Date"]) });
}
}
}
return messages;
}
CallBack:
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
MessagesHub.SendMessages();
}
}
Any Help please!
I have a winforms app which will write data into 2 different tables in same DB. My timer will count every one second. When the first machine is ready to give data, I will get it and write to the first table. When the machine 2 is ready as well, I will get it and write data to the second table. I put these two inserting processes in two different background worker processes. But I keep getting an error "ExecuteNonQuery requires an open and available Connection. The connection's current state is connecting." Below is my code.
private void timer1_Tick(object sender, EventArgs e)
{
readMachinewidth();
}
private void readMachinewidth()
{
if(M1 == "true")
{
backgroundWorker1.RunWorkerAsync();
}
if(M2 == "true")
{
backgroundWorker2.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (!oData.saveM1ProcessQty("M1", "M1"))
{
MessageBox.Show("M1 - Database Error");
return;
}
}
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
{
if (oData.saveM2ProcessQty("M2", "M2"))
{
MessageBox.Show("M2 - Database Error");
return;
}
}
May I know how I can fix it? How I can make the winforms can write data in two different tables in almost the same time in same database. I expect it is the connection open issue. But I can't figure out how to fix it. When write table 1 data the connection is open while at the same time the data for Machine 2 may be ready to write as well.
My data insertion function
public Boolean saveM1ProcessQty(string M1, string M1a)
{
try
{
string sSQL = "";
SqlCommand oCmd;
sSQL = "INSERT INTO xxx(M1, M1-1)VALUES('";
sSQL = sSQL + M1+ "','" + M1a+ "')";
oConn.ConnectionLocal.Open();
oCmd = new SqlCommand(sSQL, oConn.ConnectionLocal);
oCmd.ExecuteNonQuery();
oConn.ConnectionLocal.Close();
oCmd.Dispose();
return true;
}
catch(SqlException sqlex)
{
oConn.ConnectionLocal.Close();
Common.ErrorLog("M1 - " + sqlex.Message.ToString());
return false;
}
catch(Exception ex)
{
oConn.ConnectionLocal.Close();
Common.ErrorLog("M1 - " + ex.Message.ToString());
return false;
}
}
public Boolean saveM2ProcessQty(string M2, string M2a)
{
try
{
string sSQL = "";
SqlCommand oCmd;
sSQL = "INSERT INTO xxx(M1, M1-1)VALUES('";
sSQL = sSQL + M2+ "','" + M2a+ "')";
oConn.ConnectionLocal.Open();
oCmd = new SqlCommand(sSQL, oConn.ConnectionLocal);
oCmd.ExecuteNonQuery();
oConn.ConnectionLocal.Close();
oCmd.Dispose();
return true;
}
catch(SqlException sqlex)
{
oConn.ConnectionLocal.Close();
Common.ErrorLog("M2 - " + sqlex.Message.ToString());
return false;
}
catch(Exception ex)
{
oConn.ConnectionLocal.Close();
Common.ErrorLog("M2 - " + ex.Message.ToString());
return false;
}
}
My Connection class
public SqlConnection ConnectionLocal
{
get
{
if(_localConn == null)
{
string sconnstring =
ConfigurationManager.ConnectionStrings["local"].ToString();
_localConn = new SqlConnection(sconnstring);
}
return _localConn;
}
}
That error occurs when you are not calling SqlConnection.Open(). It has nothing to do with concurrency. Without seeing your actual database access code, I can't help you much more than that. But somewhere along the line, the connection is being created in memory but not connected.
Edit:
In re to a comment, here's the code with using blocks as appropriate. I also took the liberty of parameterizing your query to avoid SQL injection attacks.
public Boolean saveM1ProcessQty(string M1, string M1a)
{
try
{
string sSQL = "INSERT INTO xxx (M1, M1-1) VALUES ('#m1, #m1a')";
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["local"].ToString()))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sSQL, conn));
{
cmd.Parameters.AddWithValue("#m1", M1);
cmd.Parameters.AddWithValue("#m1a", M1a);
cmd.ExecuteNonQuery();
}
}
return true;
}
catch(Exception ex)
{
Common.ErrorLog("M1 - " + ex.Message.ToString());
return false;
}
}
A few months ago I made a test program for a project and everything worked fine there.
Now I am working on the program itself, so I copied the code from the test program and
changed the the names of the columns,buttons etc. so it would fit the current program.
When I try to add something into the database it does nothing on the first click, on the
second pops up an error which says that the connection is open.. I really got no idea what's
the problem. I tried to check again if I made a mistake in a column name or the database name
but everything seems to be correct.
Note: I also have a function that show data from the database and it works without any problem.
private void InsertData()
{
string NewCode = GenerateCode();
string NewSentence = txtSentence.Text;
string NewRow = NewRowNum();
try
{
string AddData = "INSERT INTO ShopSentences (BinaryStrings,Sentence,RowNumber) VALUES (#NewBinaryString,#NewSentence,#NewRowNumber)";
SqlCommand DataAdd = new SqlCommand(AddData, Connection);
DataAdd.Parameters.AddWithValue("#NewBinaryString", NewCode);
DataAdd.Parameters.AddWithValue("#NewNewSentence", NewSentence);
DataAdd.Parameters.AddWithValue("#NewRowNumber", NewRow);
Connection.Open();
DataAdd.ExecuteNonQuery();
Connection.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
//Checking the banary code in the last row
string GenerateCode()
{
string RowNo = RowFind();
int Row = int.Parse(RowNo);
int Code = Row + 1;
string Cd = Convert.ToString(Code, 2);
int Ln = Cd.Trim().Length;
if (Ln == 3)
{
Cd = "100" + Cd;
}
else if (Ln == 4)
{
Cd = "10" + Cd;
}
else if (Ln == 5)
{
Cd = "1" + Cd;
}
return Cd;
}
//Finding the last row
string RowFind()
{
Connection.Open();
string queryString = string.Format("SELECT * FROM ShopSentences");
SqlDataAdapter sda = new SqlDataAdapter(queryString, Connection);
DataTable dt = new DataTable("ShopSentences");
sda.Fill(dt);
Connection.Close();
return dt.Rows[dt.Rows.Count - 1]["RowNumber"].ToString();
}
string NewRowNum()
{
string Row = RowFind();
int CalcRow = int.Parse(Row) + 1;
Row = CalcRow.ToString();
return Row;
}
The connection that appears to be open is the one in the string RowFind().
Here are the other related things to the database:
public partial class frmShop : Form
{
System.Data.SqlClient.SqlConnection Connection;
public frmShop()
{
string DatabaseConnection = WindowsFormsApplication1.Properties.Settings.Default.BinaryStringsDictionaryConnectionString1;
Connection = new System.Data.SqlClient.SqlConnection();
Connection.ConnectionString = DatabaseConnection;
InitializeComponent();
}
private void frmShop_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'binaryStringsDictionaryDataSet.ShopSentences' table. You can move, or remove it, as needed.
this.shopSentencesTableAdapter.Fill(this.binaryStringsDictionaryDataSet.ShopSentences);
}
private void GetSentence()
{
try
{
Connection.Open();
SqlDataReader ReadSentence = null;
Int32 BinaryInt = Int32.Parse(txtBinaryString.Text);
string CommandString = "SELECT Sentence FROM ShopSentences WHERE BinaryStrings = #BinaryString";
SqlCommand Command = new SqlCommand(CommandString, Connection);
Command.Parameters.Add("#BinaryString", System.Data.SqlDbType.Int).Value = BinaryInt;
ReadSentence = Command.ExecuteReader();
while (ReadSentence.Read())
{
txtSentence.Text = (ReadSentence["Sentence"].ToString());
Fit = 1;
}
Connection.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
You are getting errors because you are reusing the same connection Connection.Open(); several times.
Your method InsertData() is doing this 3 times in the same method.
You should create a new instance of the connection object and dispose it on your methods.
Using Statement are the way to go.
private void InsertData()
{
using (var Connection = new SqlConnection(DatabaseConnection))
{
string NewCode = GenerateCode();
string NewSentence = txtSentence.Text;
string NewRow = NewRowNum();
try
{
Connection.Open();
string AddData = "INSERT INTO ShopSentences (BinaryStrings,Sentence,RowNumber) VALUES (#NewBinaryString,#NewSentence,#NewRowNumber)";
SqlCommand DataAdd = new SqlCommand(AddData, Connection);
DataAdd.Parameters.AddWithValue("#NewBinaryString", NewCode);
DataAdd.Parameters.AddWithValue("#NewNewSentence", NewSentence);
DataAdd.Parameters.AddWithValue("#NewRowNumber", NewRow);
DataAdd.ExecuteNonQuery();
//Connection.Close(); no need to close
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
You can save one more connection if you store the row returned by RowFind()
string RowFind()
{
using (var Connection = new SqlConnection(DatabaseConnection))
{
Connection.Open();
string queryString = string.Format("SELECT * FROM ShopSentences");
SqlDataAdapter sda = new SqlDataAdapter(queryString, Connection);
DataTable dt = new DataTable("ShopSentences");
sda.Fill(dt);
//Connection.Close();
return dt.Rows[dt.Rows.Count - 1]["RowNumber"].ToString();
}
}
So you would connect once instead of twice:
var Row = RowFind();
string NewCode = GenerateCode(Row);
string NewRow = NewRowNum(Row);
string NewSentence = txtSentence.Text;
Declare your connection string variable to a property so you can reuse it:
private string DatabaseConnection {get; set;}
Instead using an instance level SqlConnection you should only provide a common factory for creating a connection:
public partial class frmShop : Form
{
private string ConnectionString
{
get { return WindowsFormsApplication1.Properties.Settings.Default.BinaryStringsDictionaryConnectionString1; }
}
public frmShop()
{
InitializeComponent();
}
private SqlConnection CreateConnection()
{
var conn = new SqlConnection(ConnectionString);
conn.Open();
return conn;
}
private void frmShop_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'binaryStringsDictionaryDataSet.ShopSentences' table. You can move, or remove it, as needed.
this.shopSentencesTableAdapter.Fill(this.binaryStringsDictionaryDataSet.ShopSentences);
}
private void GetSentence()
{
try
{
using (var conn = CreateConnection())
{
var BinaryInt = int.Parse(txtBinaryString.Text);
var commandString = "SELECT Sentence FROM ShopSentences WHERE BinaryStrings = #BinaryString";
using (var Command = new SqlCommand(commandString, conn))
{
Command.Parameters.Add("#BinaryString", System.Data.SqlDbType.Int).Value = BinaryInt;
using (var readSentence = Command.ExecuteReader())
{
while (readSentence.Read())
{
txtSentence.Text = (readSentence["Sentence"].ToString());
Fit = 1;
}
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void InsertData()
{
try
{
using (var conn = CreateConnection())
{
var commandString = "INSERT INTO ShopSentences (BinaryStrings,Sentence,RowNumber) VALUES (#NewBinaryString,#NewSentence,#NewRowNumber)";
using (var comm = new SqlCommand(commandString, conn))
{
comm.Parameters.AddWithValue("#NewBinaryString", GenerateCode());
comm.Parameters.AddWithValue("#NewNewSentence", txtSentence.Text);
comm.Parameters.AddWithValue("#NewRowNumber", NewRowNum());
comm.ExecuteNonQuery();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
//Checking the banary code in the last row
string GenerateCode()
{
string RowNo = RowFind();
int Row = int.Parse(RowNo);
int Code = Row + 1;
string Cd = Convert.ToString(Code, 2);
int Ln = Cd.Trim().Length;
if (Ln == 3)
{
Cd = "100" + Cd;
}
else if (Ln == 4)
{
Cd = "10" + Cd;
}
else if (Ln == 5)
{
Cd = "1" + Cd;
}
return Cd;
}
//Finding the last row
string RowFind()
{
using (var conn = CreateConnection())
{
var commandString = "SELECT * FROM ShopSentences";
using (var comm = new SqlCommand(commandString, conn))
{
using (var sda = new SqlDataAdapter(queryString, Connection))
{
using (DataTable dt = new DataTable("ShopSentences"))
{
sda.Fill(dt);
return dt.Rows[dt.Rows.Count - 1]["RowNumber"].ToString();
}
}
}
}
}
string NewRowNum()
{
var Row = RowFind();
var CalcRow = int.Parse(Row) + 1;
return CalcRow.ToString();
}
}
But this is just the beginning you should not have any hard SQL dependency in your Form classes.
When sharing same SqlConnection instance several times in your code, instead of directly opening the you can rather check the connection state first and then open it if not already opened. For example:
if(Connection.State!= ConnectionState.Open)
Connection.Open();
Why is the where clause being ignored in this code? It seems to be ignoring the where clause on the update which means every records has been written over. How can i fix this? Any help would be greatly appreciated.
namespace ResitAssignment2
{
public partial class HomeCareVisitEddit : Form
{
public HomeCareVisitEddit()
{
InitializeComponent();
}
private void SubmitHCVA_Click(object sender, EventArgs e)
{
SqlConnection a = Database.GetConnection();
a.Open();
string sqltext;
sqltext = #"update HomeCareVisit set
PatientNo=#PatientNo,
FurtherVisitRequired=#FurtherVisitRequired,
AdvisoryNotes=#AdvisoryNotes,
Prescription=#Prescription,
TreatmentProvided=#TreatmentProvided,
ActualVisitDateTime=#ActualVisitDateTime,
Priority=#Priority,
ScheduledDateTime=#ScheduledDateTime,
TreatmentInstructions=#TreatmentInstructions,
MedicalStaffID=#MedicalStaffID
WHERE
VisitRefNo=VisitRefNo";
SqlCommand command = new SqlCommand(sqltext, a);
try
{
using (a)
{
command.Parameters.AddWithValue("#PatientNo", PatientNo.Text);
command.Parameters.AddWithValue("#FurtherVisitRequired", FurtherVisitRequired.Text);
command.Parameters.AddWithValue("#AdvisoryNotes", AdvisoryNotes.Text);
command.Parameters.AddWithValue("#Prescription", Prescription.Text);
command.Parameters.AddWithValue("#TreatmentProvided", TreatmentProvided.Text);
command.Parameters.AddWithValue("#ActualVisitDateTime",SqlDbType.DateTime );
{
DateTime.Parse(ActualVisitDateTime.Text);
};
command.Parameters.AddWithValue("#Priority", Priority.Text);
command.Parameters.AddWithValue("#ScheduledDateTime",SqlDbType.DateTime );
{
DateTime.Parse(ScheduledDateTime.Text);
};
command.Parameters.AddWithValue("#TreatmentInstructions", TreatmentInstructions.Text);
command.Parameters.AddWithValue("#MedicalStaffID", MedicalStaffID.Text);
command.Parameters.AddWithValue("#VisitRefNo", VisitRefNo.Text);
command.ExecuteNonQuery();
MessageBox.Show("Record altered");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
a.Close();
}
private void HomeCareVisitEddit_Load(object sender, EventArgs e)
{
SqlConnection a = Database.GetConnection();
a.Open();
string sqlText = "select * from HomeCareVisit where VisitRefNo =" + VisitRefNo;
SqlCommand command = new SqlCommand(sqlText, a);
SqlDataReader HomeCareVisitData = command.ExecuteReader();
while (HomeCareVisitData.Read())
{
//DateTime actual = DateTime.Parse("ActualVisitDateTime");
//DateTime scheduled = DateTime.Parse("ActualVisitDateTieme");
PatientNo.Text = HomeCareVisitData["PatientNo"].ToString();
FurtherVisitRequired.Text = HomeCareVisitData["FurtherVisitRequired"].ToString();
AdvisoryNotes.Text = HomeCareVisitData["AdvisoryNotes"].ToString();
Prescription.Text = HomeCareVisitData["Prescription"].ToString();
TreatmentProvided.Text = HomeCareVisitData["TreatmentProvided"].ToString();
ActualVisitDateTime.Text = HomeCareVisitData["ActualVisitDateTime"].ToString();
Priority.Text = HomeCareVisitData["Priority"].ToString();
ScheduledDateTime.Text = HomeCareVisitData["ScheduledDateTime"].ToString();
TreatmentInstructions.Text = HomeCareVisitData["TreatmentInstructions"].ToString();
MedicalStaffID.Text = HomeCareVisitData["MedicalStaffID"].ToString();
}
a.Close();
}
}
}
WHERE VisitRefNo=VisitRefNo"; should be WHERE VisitRefNo=#VisitRefNo";.
WHERE VisitRefNo=VisitRefNo
Should be
WHERE VisitRefNo=#VisitRefNo