我希望你原谅我的头。我在设计用于打开SQL Server数据库的代码时遇到了一些问题。如您所见,frmManageAppointment表单是从其他Winform加载的。到现在为止还挺好。加载后,代码的Connect()部分开始运行并连接到我的SQLDB。到现在为止还挺好。我有第二个脚本,该脚本在按下表单上的“保存”按钮时加载(基本上是保存各种文本框等)。我的猜测是,基于我得到的错误,代码的MakeAppointment部分中conn的第二个实例以某种方式关闭了连接。
我知道我没有正确处理该脚本,因此,我将感谢您的帮助。'''命名空间Scheduler1{公共局部类frmManageAppointment:表格{
public frmManageAppointment()
{
InitializeComponent();
}
private void frmManageAppointment_Load(object sender, EventArgs e)
{
Connect();
txtDBConnection.Text = "Connected";
}
private void ExitButton_Click(object sender, EventArgs e)
{
this.Close();
}
private void SaveButton_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(txtSurname.Text))
{
MessageBox.Show("Απαιτείται το Επίθετο του Εξεταζόμενου!");
return;
}
if (MakeAppointment())
{
MessageBox.Show("Επιτυχής Προσθήκη!");
}
else
{
MessageBox.Show("Ανεπιτυχής Προσθήκη");
}
}
public void Connect()
{
string conString = "Data Source=DIMITRIS-PC\\DIMITRISSQL;Initial Catalog=AppointmentDB;Integrated Security=True";
SqlConnection conn = new SqlConnection(conString);
conn.Open();
if (conn.State == System.Data.ConnectionState.Closed)
{
MessageBox.Show("Closed");
}
else
if (conn.State == System.Data.ConnectionState.Open)
{
MessageBox.Show("Open");
}
}
public Boolean MakeAppointment()
{
string conString = "Data Source=DIMITRIS-PC\\DIMITRISSQL;Initial Catalog=AppointmentDB;Integrated Security=True";
SqlConnection conn = new SqlConnection(conString);
string sql = "INSERT INTO Appointmentdbo(Date, Time, Name, Surname, DOB, PatientID, Comments) VALUES ('" + dtpDate.Value.Date.ToString("MM/dd/yyyy") + "','" + comboTime.Text + "','" + txtName.Text + "','" + txtSurname.Text + "','" + dtpDOB.Value.Date.ToString("MM/dd/yyyy") + "','" + txtID.Text + "','" + txtComments.Text + "')";
SqlCommand cmd = new SqlCommand(sql, conn);
return cmd.ExecuteNonQuery() > 0;
}
}
}'''
正如评论所指出的,您正在创建一个连接(conn
中的Connect()
对象,将其打开,然后conn
超出范围。这里的conn
对象是打开的连接。
这是使它生效的最短方法,但是正如评论中所指出的那样,这也不是那么好。我对此进行了布局,以确切地解释您在做什么错/为什么您的工作不起作用。在此下方,我有一个带有using
语句的示例。
public class frmManageAppointment : Form {
SqlConnection conn; //private variable available to all methods in this class
private void frmManageAppointment_Load(object sender, EventArgs e)
{
Connect();
}
private void ExitButton_Click(object sender, EventArgs e)
{
this.CloseConn(); //new method here
this.Close();
}
void CloseConn() {
//we want to close/dispose the connection obect
conn.Close();
conn.Dispose();
}
public void Connect()
{
string conString = "<constring>";
conn = new SqlConnection(conString); //removed type here so conn now the class level variable
conn.Open();
//rest of code snipped
}
public Boolean MakeAppointment()
{
string sql = "<sql string>"; //btw, the way you're generating this string is ... not ideal. Google sql injection
SqlCommand cmd = new SqlCommand(sql, conn); //conn is our global variable, which we're assuming here is still open/valid (not ideal)
return cmd.ExecuteNonQuery() > 0;
}
}
问题是您的表单将无限期地打开。如果小型应用程序连接到本地数据库,而该应用程序是唯一的连接对象,那么这可能不会有问题,但是保持连接打开状态会浪费服务器资源,并且您无法保证conn
对象在您使用时仍然有效稍后尝试在MakeAppointment()
中使用它。您可以添加检查它实际上是打开的,如果没有打开,则再次调用Connect()
,但这是一堆徒劳的工作。使用数据库(或任何网络资源)时采用的一种更好的模式/习惯是仅在需要工作时打开它们,并在完成后立即关闭/释放它们。就是说,这就是您的代码的样子。
public class frmManageAppointment : Form {
//no need for a Connect() method, conn global variable, or a CloseConn() method
//your other methods pertaining to the UI would need to be copied over
public Boolean MakeAppointment()
{
string sql = "<sql string>"; //again, what you're doing here is bad
using(SqlConnection conn = new SqlConnection("<connectionstring>") {
conn.Open();
using(SqlCommand cmd = new SqlCommand(sql, conn)) {
return cmd.ExecuteNonQuery() > 0;
}
}
}
}
[您仅在使用连接之前立即打开连接(在此示例中,您要做的唯一工作是在MakeAppointment()
中,并且通过将连接和命令包装在using
语句中,它们将被自动处置(通过在对象超出范围时调用这些对象Dispose()
方法)。