C# Desktop Application: SQL Server access suddenly gets slow - c#

My C# desktop application has a form ItemsBrowser. My application is about an Inventory system. The ItemsBrowser form loads the Items Details while user add a new sale or new purchase. Here is LoadAllItems() code: -
void LoadAllItems()
{
DBConnector dbc = new DBConnector();
AccountsBasic.Classes.DBConnector dbca = new AccountsBasic.Classes.DBConnector();
ArrayList lstItems = dbc.GetAllItems();
var AddedItems = new List<DataGridViewRow>();
Cursor.Current = Cursors.WaitCursor;
dgvItems.Rows.Clear();
for (int i=0; i<=lstItems.Count-1; i++)
{
Item itm = (Item)lstItems[i];
ItemCategory ItemCat = dbc.GetThisItemCategory(itm.ItemCategoryCode);
DataGridViewRow row = new DataGridViewRow();
row.CreateCells(dgvItems);
row.Cells[0].Value = dbca.GetThisParty(dbc.GetThisItemCategory(itm.ItemCategoryCode).SupplierCode).PartyName;
row.Cells[1].Value = ItemCat.ItemCategoryName;
row.Cells[2].Value = itm.ItemID.ToString();
row.Cells[3].Value = itm.ItemName;
row.Cells[4].Value = itm.RetailPrice.ToString();
row.Cells[5].Value = dbc.GetPresentStock_By_ItemID(itm.ItemID).ToString();
AddedItems.Add(row);
//dgvItems.Rows.Add(dbca.GetThisParty(dbc.GetThisItemCategory(itm.ItemCategoryCode).SupplierCode).PartyName, dbc.GetThisItemCategory(itm.ItemCategoryCode).ItemCategoryName, itm.ItemID.ToString(), itm.ItemName, itm.RetailPrice, dbc.GetPresentStock_By_ItemID(itm.ItemID).ToString());
}
dgvItems.Rows.AddRange(AddedItems.ToArray());
dgvItems.AutoResizeColumns();
Cursor.Current = Cursors.Default;
}
This function was working fine and in speed. But suddenly It got slow very much. By checking each line one by one in the loop, I found that when a statement accessing the database like
ItemCategory ItemCat = dbc.GetThisItemCategory(itm.ItemCategoryCode);
the database access gets very slow. Although it was running pretty fine before. There are total 955 items in the table.
ALSO A VERY STRANGE THING I HAVE NOTICED...
I have installed this application on the client's machine and it is working fine there on client's machine with no delay...
GetAllItems() Function
public ArrayList GetAllItems(string SupplierCode = "", string ItemCategory = "")
{
if (SupplierCode != "" && ItemCategory != "")
comm.CommandText = "SELECT Items.ItemID, Items.ItemName, Items.Description, Items.ItemCategoryCode, Items.OpeningStock, Items.RetailPrice FROM Items, ItemCategories WHERE Items.ItemCategoryCode = ItemCategories.ItemCategoryCode AND ItemCategories.SupplierCode = '" + SupplierCode + "' AND ItemCategories.ItemCategory = '" + ItemCategory + "' ORDER BY Items.ItemID";
else if (SupplierCode != "" && ItemCategory == "")
comm.CommandText = "SELECT Items.ItemID, Items.ItemName, Items.Description, Items.ItemCategoryCode, Items.OpeningStock, Items.RetailPrice FROM Items, ItemCategories WHERE Items.ItemCategoryCode = ItemCategories.ItemCategoryCode AND ItemCategories.SupplierCode = '" + SupplierCode + "' ORDER BY ItemCategories.SupplierCode, ItemCategories.ItemCategory";
else if (SupplierCode == "" && ItemCategory != "")
comm.CommandText = "SELECT Items.ItemID, Items.ItemName, Items.Description, Items.ItemCategoryCode, Items.OpeningStock, Items.RetailPrice FROM Items, ItemCategories WHERE Items.ItemCategoryCode = ItemCategories.ItemCategoryCode AND ItemCategories.ItemCategory = '" + ItemCategory + "' ORDER BY Items.ItemID";
else
comm.CommandText = "SELECT * FROM Items Order By ItemID";
ArrayList AllItems = new ArrayList();
conn.Open();
SqlDataReader dr;
dr = comm.ExecuteReader();
while (dr.Read())
{
Item it = new Item();
it.ItemID = dr.GetInt32(0);
it.ItemName = dr.GetString(1);
it.Description = dr.IsDBNull(2) ? "" : dr.GetString(2);
it.ItemCategoryCode = dr.IsDBNull(3) ? -1 : dr.GetInt32(3);
it.OpeningStock = dr.IsDBNull(4) ? 0 : dr.GetInt32(4);
it.RetailPrice = dr.IsDBNull(5) ? 0 : dr.GetDouble(5);
AllItems.Add(it);
}
dr.Close();
conn.Close();
return AllItems;
}
GetThisItemCategory() Function
public ItemCategory GetThisItemCategory(int ItemCategoryCode = -1, string SupplierCode = "", string ItemCategory = "")
{
if (ItemCategoryCode == -1 && SupplierCode != "" && ItemCategory != "")
comm.CommandText = "SELECT * FROM ItemCategories WHERE SupplierCode = '" + SupplierCode + "' AND ItemCategory = '" + ItemCategory + "' Order By SupplierCode, ItemCategory";
else if (ItemCategoryCode == -1 && SupplierCode == "" && ItemCategory != "")
comm.CommandText = "SELECT * FROM ItemCategories WHERE ItemCategory = '" + ItemCategory + "' Order By ItemCategory";
else// if (ItemCategoryCode != -1 && SupplierCode == "" && ItemCategory == "")
comm.CommandText = "SELECT * FROM ItemCategories WHERE ItemCategoryCode = '" + ItemCategoryCode + "' Order By SupplierCode, ItemCategory";
SqlDataReader dr;
ItemCategory ic = new ItemCategory();
ic.ItemCategoryCode = -1;
conn.Open();
dr = comm.ExecuteReader();
if (dr.Read())
{
ic.ItemCategoryCode = dr.GetInt32(0);
ic.SupplierCode = dr.GetString(1);
ic.ItemCategoryName = dr.GetString(2);
ic.OrderableStockLimit = (dr.IsDBNull(3)) ? -1 : dr.GetInt32(3);
}
dr.Close();
conn.Close();
return ic;
}
Actually, problem is not about specific function. It is about any database access, whether it is GetThisItemCategory() or GetPresentStock_By_ItemID() function.
PLEASE NOTE EARLIER IT WAS WORKING PRETTY FINE. SUDDENLY IT STARTED BEHAVING IN THIS MANNER...

You need to learn how to do "named parameters", to protect against injected sql attacks AND to get maximum plan-reuse from your RDBMS.
Here is an example:
using System;
using System.Data;
using System.Data.SqlClient;
class ParamDemo
{
static void Main()
{
// conn and reader declared outside try
// block for visibility in finally block
SqlConnection conn = null;
SqlDataReader reader = null;
string inputCity = "London";
try
{
// instantiate and open connection
conn = new
SqlConnection("Server=(local);DataBase=Northwind;Integrated Security=SSPI");
conn.Open();
// don't ever do this
// SqlCommand cmd = new SqlCommand(
// "select * from Customers where city = '" + inputCity + "'";
// 1. declare command object with parameter
SqlCommand cmd = new SqlCommand(
"select * from Customers where city = #City", conn);
// 2. define parameters used in command object
SqlParameter param = new SqlParameter();
param.ParameterName = "#City";
param.Value = inputCity;
// 3. add new parameter to command object
cmd.Parameters.Add(param);
// get data stream
reader = cmd.ExecuteReader();
// write each record
while(reader.Read())
{
Console.WriteLine("{0}, {1}",
reader["CompanyName"],
reader["ContactName"]);
}
}
finally
{
// close reader
if (reader != null)
{
reader.Close();
}
// close connection
if (conn != null)
{
conn.Close();
}
}
}
}
http://csharp-station.com/Tutorial/AdoDotNet/Lesson06
You can read a few things about dynamic sql in this article.
http://sqlmag.com/database-performance-tuning/don-t-fear-dynamic-sql
(There is a mini overlap between your .cs C# "inline" sql vs this article...it'll give you a few things to research further if you're inclined)
.....
Finally, you need to learn the basics of "index tuning".
You can get an intro to that here:
https://sqlserverperformance.wordpress.com/2010/04/06/a-dmv-a-day-%E2%80%93-day-7/
As a guess, I would create an index on
ItemCategories.ItemCategoryCode
and a seperate index on
ItemCategories.SupplierCode
APPEND:
Finally, can you try this version of the code?
You want to get-rid of DataReaders as soon as possible, so your connection pool does not run out of connections.
public ItemCategory GetThisItemCategory(int ItemCategoryCode = -1, string SupplierCode = "", string ItemCategory = "")
{
using (SqlCommand cmd = new SqlCommand("MyConnectionString")
{
/* TO DO !!! , build your sql-string and parameter list here */
using (IDataReader dataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
if /*while*/ (dataReader.Read())
{
ic.ItemCategoryCode = dr.GetInt32(0);
ic.SupplierCode = dr.GetString(1);
ic.ItemCategoryName = dr.GetString(2);
ic.OrderableStockLimit = (dr.IsDBNull(3)) ? -1 : dr.GetInt32(3);
}
if (dataReader != null)
{
try
{
dataReader.Close();
}
catch { }
}
}
cmd.Close();
}
return ic;
}

Related

Execute Scalar can't return the existing row

I have faced a problem regarding mark duplicate data. In my project, the record which already exists can't be recorded twice. I have followed multiple posts of stackoverflow and come to know that I have to use executescalar to do that.. I have used executescalar but it can't handle the existing data. Would you please help me to sort it out.
Here is my part of code:
{
appointmentdate = dtappointmentdate.Value;
today = DateTime.Now;
String prob = txtproblemdefination.Text;
String rec = "";
if (appointmentdate < today)
{
MessageBox.Show("Please Enter Correct Date.");
}
else
{
SqlCommand check_User_Name = new SqlCommand("SELECT count(*) FROM appointmentTable WHERE PatientName = '" + patientname + "'And (DoctorName = '" + docname + "'And AppointmentDateSet = '" + appointmentdate + "')", sqlCon);
check_User_Name.Parameters.AddWithValue("#patname", patientname);
check_User_Name.Parameters.AddWithValue("#docname", docname);
check_User_Name.Parameters.AddWithValue("#appointmentdate", appointmentdate);
if (sqlCon.State != ConnectionState.Open)
{
sqlCon.Open();
}
int UserExist = (Int32)check_User_Name.ExecuteScalar();
if (UserExist > 0)
{
MessageBox.Show("You can't make appointment twice a day. ");
}
else
{
SqlCommand insertCommand = new SqlCommand("insert into appointmentTable(PatientName,DoctorName,ClinicLocation,AppointmentDateSet,Problem,Recommendation) values(#docname, #patname, #doclocation, #appointmentdate,#prob,#rec)");
insertCommand.Parameters.AddWithValue("#patname", patientname);
insertCommand.Parameters.AddWithValue("#docname", docname);
insertCommand.Parameters.AddWithValue("#doclocation", doclocation);
insertCommand.Parameters.AddWithValue("#appointmentdate", appointmentdate);
insertCommand.Parameters.AddWithValue("#prob", prob);
insertCommand.Parameters.AddWithValue("#rec", rec);
int row = objdbaccess.executeQuery(insertCommand);
if (row == 1)
{
MessageBox.Show("Appointment is Successfully Done.");
}
else
{
MessageBox.Show("Error!Please try again later.");
}
sqlCon.Close();
}
}
You should change your code to:
I am assuming appointmentdate is of type DateTime if not you can choose the correct type from here
using(var check_User_Name= SqlCommand("SELECT count(*) FROM appointmentTable WHERE PatientName = #patname And DoctorName = #docname And AppointmentDateSet = #appointmentdate )", sqlCon)
{
check_User_Name.Parameters.Add("#patname", DbType.String).Value = patientname;
check_User_Name.Parameters.Add("#docname", DbType.String).Value = docname;
check_User_Name.Parameters.Add("#appointmentdate", DbType.DateTime).Value = appointmentdate;
con.Open();
int UserExist = (int)check_User_Name.ExecuteScalar();
// Followed by your code
}

How to make only one method to populate Items of a ComBobox as well as a ListBox?

This procedure below fills a ComboBox with values from a database.
There is also one for ListBoxes, and it's completely identical except "box" is a ListBox.
Both CB and LB classes have Items and both inherit ListControl which doesn't have Items.
How can I get rid of the duplicate code there?
private void UpdateBox (ComboBox box, string select, string from, string order = "")
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
if (order == "") order = select;
using (SqlCommand command = new SqlCommand("SELECT " + select +
" FROM " + from + " ORDER BY " + order, conn))
{
SqlDataReader dataReader = command.ExecuteReader();
box.Items.Clear();
while (dataReader.Read())
{
box.Items.Add(dataReader[select]);
}
}
}
}
Here is the other one:
private void UpdateBox (ListBox box, string select, string from, string order = "")
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
if (order == "") order = select;
using (SqlCommand command = new SqlCommand("SELECT " + select +
" FROM " + from + " ORDER BY " + order, conn))
{
SqlDataReader dataReader = command.ExecuteReader();
box.Items.Clear();
while (dataReader.Read())
{
box.Items.Add(dataReader[select]);
}
}
}
}
Both Items Collections implement IList
So instead of passing the ComboBox/ListBox, you can just pass comboBox1.Items or listBox1.Items to your method.
private void UpdateBox (IList items, string select, string from, string order = "")
...
items.Clear();
while (dataReader.Read())
{
items.Add(dataReader[select]);
}
You can use #Holger answer.
For speed performances you can use that refactored:
private void PopulateItems(List<IList> listItems,
string column,
string table,
string orderByColumn = "")
{
using ( var connection = new SqlConnection(connectionString) )
{
connection.Open();
if ( orderByColumn == "" )
orderByColumn = column;
string sql = $"SELECT {column} FROM {table} ORDER BY {orderByColumn}";
using ( var command = new SqlCommand(sql, connection) )
{
var reader = command.ExecuteReader();
foreach ( var items in listItems )
items.Clear();
while ( reader.Read() )
foreach ( var items in listItems )
items.Add(reader[column]);
}
}
}
Usage:
var listItemsToPopulate = new List<IList>()
{
comboBox1.Items,
listBox1.Items
};
PopulateLists(listItemsToPopulate, "", "", "");
I would restructure this code. You're trying to do too much in 1 function.
Split fetching from the DB from manipulating the control. Now the GetDbItems function is independent - easier to move to a separate class & not bound to the UI directly.
Something like this:
IList<string> items = GetDbItems("a", "b", "c");
if (items.Any())
{
control.Items.Clear();
control.Items.Add(items);
}
private IList<string> GetDbItems(string select, string from, string order = "")
{
var result = new List<string>();
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
if (order == "") order = select;
using (SqlCommand command = new SqlCommand("SELECT " + select +
" FROM " + from + " ORDER BY " + order, conn))
{
SqlDataReader dataReader = command.ExecuteReader();
while (dataReader.Read())
{
result.Add(dataReader[select]);
}
}
}
return result;
}
This was just typed into the edit box - I can't guarantee it'll compile. I just wanted to give you a head start.

How to check if a value in a textbox already exists in a connected database

So I am currently puzzled to the logic of my program, I have ran through it multiple times but I am not too sure. I basically want to be able to notify the user saying that the contact number they have entered already exists in the database. I have gotten close I am sure as I have done a lot of research but I do not think what I have done is actually checking the database but rather just telling it to match to anything that is in the textbox rather than checking the database.
Just to clarify I do not want to extract data from the database and put it into the textbox. Thanks.
Update: Two different programs for two different suggested solutions.
(Possible Solution 1) Updated contact number is unique method using COUNT:
private void CheckContactNumber()
{
string checkContactNum = "SELECT COUNT(*) FROM Employee WHERE ContactNumber = " + addContactNum.Text + " "; //01234567890
OleDbCommand cmd = new OleDbCommand(checkContactNum, conn);
conn.Open();
OleDbDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
int countDup = (int)dr[0];
if (countDup > 0 && addContactNum.Text != "")
{
err += "Contact number is already listed in the database\r\n";
errorContactNum.Visible = true;
uniqueContactNumber = false;
}
else if (countDup == 0 && addContactNum.Text != "")
{
errorContactNum.Visible = false;
uniqueContactNumber = true;
}
}
conn.Close();
}
(Possible Solution 2)Update to 2nd suggested solution:
if (err == "")
{
// you miss s here
string addEmployee = "if not exists(select LastName from Employee where LastName = #LastName)INSERT INTO Employee(FirstName, LastName, Role, DateOfHire, ContactNumber)" +"VALUES(#FirstName, #LastName, #Role, #DateOfHire, #ContactNumber)";
OleDbCommand cmd = new OleDbCommand(addEmployee, conn);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
cmd.Parameters.Add("#FirstName", OleDbType.VarChar).Value = addFirstName.Text;
cmd.Parameters.Add("#LastName", OleDbType.VarChar).Value = addLastName.Text;
cmd.Parameters.Add("#Role", OleDbType.VarChar).Value = addRole.Text;
cmd.Parameters.Add("#DateOfHire", OleDbType.VarChar).Value = addDateOfHire.Text;
cmd.Parameters.Add("#ContactNumber", OleDbType.VarChar).Value = addContactNum.Text;
conn.Open();
// i removed the duplicated code
if (cmd.ExecuteNonQuery() != 1)
{
err += "Contact number is already listed in the database\r\n";
errorContactNum.Visible = true;
}
conn.Close();
addFirstName.Text = String.Empty;
addLastName.Text = String.Empty;
addRole.Text = String.Empty;
addContactNum.Text = String.Empty;
addRole.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
}
//Save It
else
{
MessageBox.Show(err);
}
}
So this would be acceptable for adding to my database as all criterion is met but it doesnt accept it, I'm assuming it runs the else code right at the bottom of AddEmployee method
Here is an Image of my database which is linked to my program.
update your function from your end
private void CheckContactNumber()
{
string checkContactNum = "SELECT COUNT(*) FROM Employee WHERE ContactNumber = " + addContactNum.Text + " "; //01234567890
OleDbCommand cmd = new OleDbCommand(checkContactNum, conn);
conn.Open();
OleDbDataReader dr = cmd.ExecuteReader();
//if (dr.Read() && addContactNum.Text != "")
if (dr.Read())
{
int count = (int)dr[0];
if(count>0)
{
err += "Contact number is already listed in the database\r\n";
errorContactNum.Visible = true;
uniqueContactNumber = false;
}
}
conn.Close();
}
Updated Answer
private void CheckContactNumber()
{
DataSet myDataSet = new DataSet();
try
{
string strAccessSelect = "select count(*) from Employee where ContactNumber='" + addContactNum.Text + "'";
OleDbCommand myAccessCommand = new OleDbCommand(strAccessSelect, conn);
OleDbDataAdapter myDataAdapter = new OleDbDataAdapter(myAccessCommand);
conn.Open();
myDataAdapter.Fill(myDataSet, "Employee");
}
catch (Exception ex)
{
Console.WriteLine("Error: Failed to retrieve the required data from the DataBase.\n{0}", ex.Message);
return;
}
finally
{
conn.Close();
}
DataTable dt = myDataSet.Tables[0];
if (dt != null)
{
if (int.Parse(dt.Rows[0][0].ToString()) > 0)
{
string err = "Contact Number Already exist..";
}
}
}
You can merge two codes in one code , by using if not exist method in sql server like this
string addEmployee = "if not exists(select LastName from Employee where
LastName=#LastName)INSERT INTO Employee (FirstName, LastName, Role,
DateOfHire, ContactNumber)" +"VALUES (#FirstName, #LastName, #Role, #DateOfHire, #ContactNumber)";
if (cmd.ExecuteNonQuery()!=1){
// the employee exist in database
}

How to prevent Sqlite Database is locked?

i got one thread reading on the database. When i click on the menustrip it shows an error "Database is locked." and it only happen sometimes. Any way to prevent the database lock? I have try WAL but its not working.
Reading:
private void checkPort(string ipIN, char[] input, string output)
{
try
{
bool building = false;
Thread beep = new Thread(Beep);
using (SQLiteConnection c = new SQLiteConnection(dbconnection))
{
c.Open();
string query = "select * from ALL_IO(nolock)";
using (SQLiteCommand cmd = new SQLiteCommand(query, c))
{
using (SQLiteDataReader dr = cmd.ExecuteReader())
{
int Contact;
while (dr.Read())
{
string _IP = dr.GetString(0);
string _IO_I = dr.GetString(1);
string _BuildingName = dr.GetString(4);
int IO_I = Convert.ToInt32(dr.GetString(1).Replace("DI ", ""));
if (dr.GetString(3) == "NC")
{
Contact = 1;
}
else
{
Contact = 0;
}
_tableName = dr.GetString(8);
string _name = dr.GetString(5);
var _active = dr.GetString(6);
var _status = dr.GetString(7);
if (_active == "Yes" && _status == "Enable")
{
//Some condition check here
}
}
catch { }
}
Writing:
void contexMenuuu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
data = "";
ToolStripItem item = e.ClickedItem;
using (SQLiteConnection c = new SQLiteConnection(dbconnection))
{
c.Open();
string sql = "select * from " + Properties.Settings.Default.TableName + "(nolock) where Name= '" + Properties.Settings.Default.LabelName.Replace(" DO", "") + "' ";
using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
{
using (SQLiteDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
_controllerIP = dr.GetString(0);
_IO = dr.GetString(1);
_IO_O = dr.GetString(2).Replace("DO ", "");
_Name = dr.GetString(4);
_Interval = Convert.ToInt32(dr.GetString(9));
}
}
}
}
if (item.Text == "Bypass Enable")
{
using (SQLiteConnection c = new SQLiteConnection(dbconnection))
{
//c.DefaultTimeout = 2000;
c.Open();
string sql = "update ALL_IO SET Active='Yes', Status='Bypass' where ControllerIP='" + _controllerIP + "' and DI='" + _IO + "';";
using (SQLiteCommand cmd = new SQLiteCommand(sql, c))
{
lock (lockobj)
{
//SQLiteConnection.ClearAllPools();
cmd.ExecuteNonQuery(); //Error occur here
}
}
}
}
Once the functionality is finished you must close the Database connect for avoid database lock issue. For executing the query you opened the database connection after that you didn't close it. so you need to close.

data reader has rows but comparison of its values is never true

I am creating a module for booking rooms in hotel.After selecting the rooms, the room numbers appear in a label. On clicking the OK button, the following code executes. When I am checking the availability of rooms, even if it is "No", flag does'nt get initialized to 1. Can anyone guide me where am I going wrong.
protected void ok_room(object sender, EventArgs e)
{
if (Label1.Text != "")
{
int result = 0;
int flag = 0;
string[] room = Label1.Text.Split(new char[] { ' ' });
cmd = new SqlCommand();
cmd1 = new SqlCommand();
cmd1.Connection = con;
cmd.Connection = con;
for (int i = 0; i < room.Length; i++)
{
cmd1.CommandText = "select room_availability from rooms where room_num='" + room[i] + "' ";
dr = cmd1.ExecuteReader();
while (dr.Read())
{
if (dr[0].ToString().Equals("No"))//this is not working
flag = 1;
}
dr.Close();
}
Response.Write(flag);
if (flag == 0)
{
for (int i = 0; i < room.Length; i++)
{
cmd.CommandText = "update rooms set room_availability='No' where room_num='" + room[i] + "'";
cmd.ExecuteNonQuery();
result = 1;
}
}
else
{
Label2.Text = "Some of the selected rooms are not available. Kindly try again";
Label1.Visible=false;
}
if (result == 1)
{
isRoomAvailable = true;
Label2.Text = " Room(s) " + Label1.Text + " is/are booked";
Label1.Visible = false;
}
}
else
Response.Write("<script>alert('Select a room first.')</script>");
}
I would do more of the logic in SQL, this would simplify the code:
// Create a condition looking like this: room_num IN('1', '2', '3')
string roomsCondition = "room_num IN (' + Label1.Text.Replace(" ", "', '") + "')";
cmd1.CommandText =
#"SELECT SUM(CASE WHEN room_availability='Yes' THEN 1 ELSE 0 END) As available,
SUM(CASE WHEN room_availability='No' THEN 1 ELSE 0 END) As not_available
FROM rooms WHERE " + roomsCondition;
This query returns the number of available and non available rooms. It should then be easier to formulate the logic than by the use of flags.
Also have a look at the ExecuteScalar method. It makes it even easier than with the query I have shown above:
using (SqlConnection conn = new SqlConnection(connString)) {
string sql = "SELECT COUNT(*) FROM rooms WHERE room_availability='Yes' AND " +
roomsCondition;
SqlCommand cmd = new SqlCommand(sql, conn);
conn.Open();
int availableRooms = (int)cmd.ExecuteScalar();
if (availableRooms > 0) {
cmd.CommandText =
#"UPDATE rooms
SET room_availability='No'
WHERE availability='Yes' AND " + roomsCondition;
cmd.ExecuteNonQuery();
} else {
...
}
}

Categories