COUNT(*) not working in C# - c#

Hi Believe the problem is with the C# code itself and not the SQL statement, as I have outputted the SQL to the screen and run it direct into the database.
For example
SELECT COUNT(*)
FROM meeting_room.meeting_acceptance
WHERE meeting_id = 'AAMkADY3MDk3NTdiLTE4M2ItNDk4ZS1hNmZjLWJmMDhkYTBiMDVjYgBGAAAAAAB+oqKzNnIvRZgdzn8wIE0XBwC62mlG2pRhSKvV6Bc2NH7rAAAALqU/AAC62mlG2pRhSKvV6Bc2NH7rAAAp5DTDAAA=';
Returns 1, although when outputting the "NoRows" variable, 0 still appears, any ideas?
if ((Appoint.End > DateTime.Now) && (Appoint.Start < DateTime.Now))
{
MySql.Data.MySqlClient.MySqlConnection mycon3 = new MySqlConnection(GetConnectionString());
if (mycon3.State != ConnectionState.Open)
try
{
mycon3.Open();
}
catch (MySqlException ex)
{
throw (ex);
}
using (mycon3)
sql = "SELECT count(*) from meeting_room.meeting_acceptance where meeting_id = '" + Appoint.Id + "';";
Label1.Text = sql;
using (MySqlCommand mcmd = new MySqlCommand(sql, mycon3))
try
{
using (MySqlDataReader datareader = mcmd.ExecuteReader())
{
while (datareader.Read())
{
NoRows = Convert.ToInt32(datareader.GetValue(0));
}
}
}
catch
{
Error.Text = "SQL Exception 2" ;
sqlerror = true;
}
Success.Text = NoRows.ToString();
if ( NoRows == 0 )
{
ConfirmLink.Text = "<div align=\"center\"><img src=\"Confirm.jpg\" alt=\"confirm\" /></div>";
if (DateTime.Now.AddMinutes(-2) > Appoint.Start)
{
Error.Text = "Would have deleted meeting";
// Appoint.CancelMeeting("The meeting you created for the " + resource_name + " on " + Appoint.Start + " Subject: " + Appoint.Subject + " has been deleted as you did not accept the meeting");
}
}
}

You need to use ExecuteScalar method
int count = (int) (mcmd.ExecuteScalar() ?? 0);
Also you have not enclosed the using block properly..Your code should look like
using(MySqlConnection mycon3 = new ....)
{
try
{
mycon3.Open();
//your commands
}
catch(SqlException e){}
}
Also your query is vulnerable to sql injection attack..Consider using SqlParameter

Convert.ToInt32(cmd.ExecuteScalar());
if you try to do explict conversion then it make a exception. Convert.ToInt32 will gave you 0 if result is null.
Your code doesn't use SQL-Parameter so it will be unsafe. use Sql parameter to make your code safer from Sql-injection.

Related

Update row in Access table using OleDb

I try to update a row in my Access, my code is running fine and I have to Exception, But is nothing change un my database
This is my method it calls from a form in a Winform project
public static void UpdateNextReportNumber(int machineNumber, string reportNumber)
{
try
{
using (OleDbConnection openCon = new OleDbConnection(localConnectionString))
{
string saveStaff = "UPDATE [Calibration] " +
"SET [NextReportNumber]=#report " +
"where [MachineNumber]=#machine";
using (OleDbCommand querySaveStaff = new OleDbCommand(saveStaff))
{
querySaveStaff.Connection = openCon;
querySaveStaff.Parameters.AddWithValue("#machine", 16);
querySaveStaff.Parameters.AddWithValue("#report",2);//Convert.ToInt32(reportNumber.Remove(0, 3)) + 1
openCon.Open();
int recordsAffected = querySaveStaff.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
//WriteLog(ex.StackTrace, ex.Message);
throw ex;
}
}
this is how my Calibration table looks like
my code pass this line
int recordsAffected = querySaveStaff.ExecuteNonQuery();
But in recordsAffected I have value 0
I have no idea what to do
I tried to execute using Access this query
UPDATE [Calibration]
SET [NextReportNumber]=2
where [MachineNumber]=36
And its work fine
I also used
public static void AddCalibration(Calibration calibration)
{
try
{
using (OleDbConnection openCon = new OleDbConnection(localConnectionString))
{
string saveStaff = "INSERT into [Calibration] ([MachineNumber] ,[LastCalibrationDate] ,[NextCalibrationDate])" +
"VALUES (#MachineNumber, #LastCalibrationDate, #NextCalibrationDate)";
using (OleDbCommand querySaveStaff = new OleDbCommand(saveStaff))
{
querySaveStaff.Connection = openCon;
querySaveStaff.Parameters.AddWithValue("#MachineNumber", calibration.MachineNumber);
querySaveStaff.Parameters.AddWithValue("#LastCalibrationDate", calibration.LastCalibrationDate);
querySaveStaff.Parameters.AddWithValue("#NextCalibrationDate", calibration.NextCalibrationDate);
openCon.Open();
int recordsAffected = querySaveStaff.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
//WriteLog(ex.StackTrace, ex.Message);
throw ex;
}
}
And it works fine also...
Thanks for help...
In OleDb parameters are not recognized by their name but by their position in the parameters collection. You should simply change the line order of your parameters
querySaveStaff.Parameters.AddWithValue("#report",2);
querySaveStaff.Parameters.AddWithValue("#machine", 16);
In your current query the report's parameter is used in the Where statement not in the update part and of course nothing is updated because there is no record with WHERE MachineNumber = 2
Indeed, in OleDb you usually specify the parameters placeholder with a single ? not with the #something syntax, but Access, probably for easier portability with Sql Server accepts also the # syntax, still the positions in parameter's collection should be the correct one expected in the query text.

Check access database for a name

I have an access table called LoginTable with text columns named Username, Password and a integer column called group. A windows form called AddUser with a textbox called Username_txtBx and a combobox called Department_cmbBx. and also a button called Add_btn . I can add a user with the following code in the button click event.
But how would I go about having it Search the database to check if the Username already exists and if it does throw a messagebox telling the user it does and if it doesn't run the code below. I have found a lot of examples for SQL databases but none for an Access database.
try
{
int g = new int();
if (Department_cmbBx.SelectedItem.ToString() == "Office")
{
g = 1;
}
else if (Department_cmbBx.SelectedItem.ToString() == "Stores")
{
g = 2;
}
else if (Department_cmbBx.SelectedItem.ToString() == "Workshop")
{
g = 3;
}
else if (Department_cmbBx.SelectedItem.ToString() == "Management")
{
g = 4;
}
else if (Department_cmbBx.SelectedItem.ToString() == "Admin")
{
g = 5;
}
connection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
command.CommandText = "insert into LoginTable(Username,[Password],[Group]) values ('" + Username_txtBx.Text + "','password'," + g + ")";
command.ExecuteNonQuery();
connection.Close();
Username_txtBx.Text = "";
Department_cmbBx.Text = "";
}
catch (Exception ex)
{
MessageBox.Show("error " + ex);
}
First, your if statements can be replaced with a more efficient and readable switch statement.
Second, you can use a OleDbDataReader with the following select query to check if the username already exists in your table.
Please note I am using Command.Parameters.Add which is more reliable and best practice when writing SQL commands as string.
int g;
bool UserExists = false;
switch(Department_cmbBx.SelectedItem.ToString())
{
case "Office":
g = 1;
break;
case "Stores":
g = 2;
break;
case "Workshop":
g = 3;
break;
case "Management":
g = 4;
break;
case "Admin":
g = 5;
break;
default:
MessageBox.Show("error: an invalid value.");
break;
}
using (OleDbConnection connection = new OleDbConnection(connectionString))
{
using (OleDbCommand command = new OleDbCommand("select [Username] from LoginTable where Username=#Username" , connection))
{
command.Parameters.Add("#Username", Username_txtBx.Text);
connection.Open();
using(OleDbDataReader reader = command.ExecuteReader())
{
// If at least 1 row was returned, this means the user exists in the table.
while (reader.Read())
{
UserExists = true;
}
}
if (!UserExists)
{
// The user does not exists - you can create it.
command.Parameters.Clear();
command.CommandText = "insert into LoginTable([Username],[Password],[Group]) values (#Username,#Username,#G)";
command.Parameters.Add("#Username", Username_txtBx.Text);
command.Parameters.Add("#Password", "password");
command.Parameters.Add("#G", g);
command.ExecuteNonQuery();
}
else
{
// Show an error message - the user already exists
MessageBox.Show("The user you eneterd already exists.");
}
}
}
Thanks Mason I couldn't get your code to work for some reason but did use the switch statement out of it and a select query like others have said. I ended up using the following code
bool UserExists = false;
command.CommandText = "Select [Username] from LoginTable where Username = '" + Username_txtBx.Text + "'";
OleDbDataReader reader = command.ExecuteReader();
int g = new int();
while (reader.Read())
{
UserExists = true;
}
connection.Close();
if (!UserExists)
{

SqlDataReader Index Out Of Range Exception when correct column count is returned

I have a stored procedure that returns correct column count, but the code below works most of the times, but RANDOMLY throws exception below. We had upgraded to .NET 4.6 recently, and we notice the exception afterwards.
Questions:
1 Where and why does the exception occur?
2 Based on source code at the bottom, how is it possible that SQL client receives empty metaData from server side?
Stored procedure GetUser:
CREATE PROCEDURE [dbo].[GetUser]
#UserID int
AS
BEGIN
SET NOCOUNT ON;
DECLARE #UserIDChar NVARCHAR(255);
SET #UserIDChar = convert(nvarchar(255), #UserID);
SELECT TOP 1
A.Value1 As FirstName,
A.Value2 As LastName
-- three more columns omitted here
FROM dbo.Activity as A
WHERE A.ActivityValue = #UserIDChar --ActivityValue is NVARCHAR(255) type
ORDER BY A.DateCreated DESC
SET NOCOUNT OFF;
END
C# web layer:
using (var cn = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "GetUser"; //the proc returns one row that consists of two columns
cmd.Connection = cn;
cmd.Parameters.AddWithValue("#UserID", userId);
cn.Open();
using (IDataReader dr = cmd.ExecuteReader(CommandBehavior.SingleResult))
{
if (dr.Read()) //check if row is available
{
string firstName = (string)dr[0];
string lastName = (string)dr[1];
// three more columns omitted here
return firstName + " " + lastName;
}
}
}
Error:
Exception Type: System.IndexOutOfRangeException
Message: Index was outside the bounds of the array.
Data: System.Collections.ListDictionaryInternal
TargetSite: Void CheckDataIsReady(Int32, Boolean, Boolean, System.String)
Source: System.Data
Source Code below:
private void CheckDataIsReady(int columnIndex, bool allowPartiallyReadColumn = false, bool permitAsync = false, string methodName = null) {
if (_isClosed) {
throw ADP.DataReaderClosed(methodName ?? "CheckDataIsReady");
}
if ((!permitAsync) && (_currentTask != null)) {
throw ADP.AsyncOperationPending();
}
Debug.Assert(!_sharedState._dataReady || _metaData != null, "Data is ready, but there is no metadata?");
if ((!_sharedState._dataReady) || (_metaData == null)) {
throw SQL.InvalidRead();
}
if ((columnIndex < 0) || (columnIndex >= _metaData.Length)) {
throw ADP.IndexOutOfRange();
}
if ((IsCommandBehavior(CommandBehavior.SequentialAccess)) && // Only for sequential access
((_sharedState._nextColumnDataToRead > columnIndex) || (_lastColumnWithDataChunkRead > columnIndex) || // Read past column
((!allowPartiallyReadColumn) && (_lastColumnWithDataChunkRead == columnIndex)) || // Partially read column
((allowPartiallyReadColumn) && (HasActiveStreamOrTextReaderOnColumn(columnIndex))))) { // Has a Stream or TextReader on a partially-read column
throw ADP.NonSequentialColumnAccess(columnIndex, Math.Max(_sharedState._nextColumnDataToRead, _lastColumnWithDataChunkRead + 1));
}
}
http://referencesource.microsoft.com/#System.Data/System/Data/SqlClient/SqlDataReader.cs,577d642dce99ed0d
The lack of a schema name could be messin' with you.
Also, some debugging tips in the C# code below.
Supply a schema name for the stored procedure.
IF EXISTS (
SELECT * FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_TYPE = N'PROCEDURE' and ROUTINE_SCHEMA = N'dbo' and ROUTINE_NAME = N'GetUser'
)
BEGIN
DROP PROCEDURE [dbo].[GetUser]
END
GO
CREATE PROCEDURE dbo.GetUser()
AS
SELECT TOP 1
FirstName, LastName
FROM
User
--omitted WHERE userid = #id
GO
Change your c# to:
using (var cn = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "dbo.GetUser";
cmd.Connection = cn;
cn.Open();
using (IDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
string temp = string.Empty;
int fc = dr.FieldCount;
if (fc>0)
{
object val2 = dr[0];
temp = val1.GetType().ToString();
}
if (fc>1)
{
object val2 = dr[1];
temp = val2.GetType().ToString();
}
temp = "did I get here?";
string firstName = (string)dr[0];
string lastName = (string)dr[1];
return firstName + " " + lastName;
}
}
}
I think this line is messing you up in your stored procedure:
A.Value2 Ad LastName
Should be:
A.Value2 as LastName
You haven't specify parameter userid in C# code please use CommandParameter and then try to do
Give this a try
Might not fix but you will get information and at least it will fail gracefully
try
{
cn.Open();
string firstName = "not";
string lastName = "found";
using (SQLDataReader dr = cmd.ExecuteReader(CommandBehavior.SingleResult))
{
if (dr.Read()) //if there is a row, there are two columns. Thus index is used below
{
Debug.WriteLine(dr.FieldCount);
firstName = rdr.IsDBNull(0) ? string.Empty : rdr.GetString(0);
lastName = rdr.IsDBNull(1) ? string.Empty : rdr.GetString(1);
}
}
}
catch (SqlException ex)
{
Debug.WriteLine("GetUser " + Environment.NewLine + ex.Message);
}
catch (Exception ex)
{
Debug.WriteLine("GetUser" + Environment.NewLine + ex.Message);
throw ex;
}
finally
{
cn.Close();
}
return firstName + " " + lastName;

Is it possible to modify an MS Access database schema using ADO.NET?

I need to modify the schema of an MS Acess database (.mdb) via code.
Since the Jet Engine DDL statements (ALTER TABLE, etc.) are quite poorly documented, I'd prefer to use some kind of object library like DAO (myDatabase.TableDefs("myTable").Fields.Append(myNewField)) or ADOX (myCatalog.Tables("myTable").Columns.Append(myNewField)) or SMO (which is only available for SQL Server, syntax similar - you get the idea).
Is there something similar like ADOX for ADO.NET or am I stuck with using DDL statements or referencing the old DAO/ADOX libraries?
I have had decent success with straight ddl statements. Your right the syntax requires a smidge of googling to tease out but I have been handling updates to a local db this way for a while. Is there a specific update you are having issues with?
Basically I wrote a few helper functions to check the structure of a table and append fields if needed.
public bool doesFieldExist(string table, string field)
{
bool ret = false;
try
{
if (!openRouteCon())
{
throw new Exception("Could not open Route DB");
}
DataTable tb = new DataTable();
string sql = "select top 1 * from " + table;
OleDbDataAdapter da = new OleDbDataAdapter(sql, routedbcon);
da.Fill(tb);
if (tb.Columns.IndexOf(field) > -1)
{
ret = true;
}
tb.Dispose();
}
catch (Exception ex)
{
log.Debug("Check for field:" + table + "." + field + ex.Message);
}
return ret;
}
public bool checkAndAddColumn(string t, string f, string typ, string def = null)
{
// Update RouteMeta if needed.
if (!doesFieldExist(t, f))
{
string sql;
if (def == null)
{
sql = String.Format("ALTER TABLE {0} ADD COLUMN {1} {2} ", t, f, typ);
}
else
{
sql = String.Format("ALTER TABLE {0} ADD COLUMN {1} {2} DEFAULT {3} ", t, f, typ, def);
}
try
{
if (openRouteCon())
{
OleDbCommand cmd = new OleDbCommand(sql, routedbcon);
cmd.ExecuteNonQuery();
string msg = "Modified :" + t + " added col " + f;
log.Info(msg);
if (def != null)
{
try
{
cmd.CommandText = String.Format("update {0} set {1} = {2}", t, f, def);
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
log.Error("Could not update column to new default" + t + "-" + f + "-" + e.Message);
}
}
return true;
}
}
catch (Exception ex)
{
log.Error("Could not alter RouteDB:" + t + " adding col " + f + "-" + ex.Message);
}
}
else
{
return true;
}
return false;
}

Syntax Error while comparison values from different tables

I'm getting a "syntax error" while using the code below.
it suppoused to avoid adding row when you entered all the values of this specific protein(it is a project combined Biology and Programming.
'serialPro' is a textbox which contains a number,but saved as string.
'Reset_Click' resetes all textboxes.
THE CODE:
if ((serialPro.Text == String.Empty) || (codon1.Text == String.Empty))
{
MessageBox.Show("You didn't fill all the fields","Attention"
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
Reset_Click(sender, e);
}
else
{
string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Projects_2012\\Project_Noam\\Access\\myProject.accdb";
OleDbConnection myConnection = new OleDbConnection(connectionString);
myConnection.Open();
string mySQL = " SELECT COUNT(tblOrderAA.orderAASerialPro) AS orderAASerialPro1 FROM tblOrderAA" +
"WHERE tblOrderAA.orderAASerialPro=" + Convert.ToInt32(serialPro.Text) +
" SELECT (tblProInfo.proInfoSerialNum) FROM tblProInfo WHERE tblProInfo.proInfoSerialNum=" +
Convert.ToInt32(serialPro.Text);
OleDbCommand datacommand = new OleDbCommand(mySQL, myConnection);
OleDbDataReader dataReader = datacommand.ExecuteReader();
dataReader.Read();
if (dataReader.GetInt32(0) == dataReader.GetInt32(1))
{
MessageBox.Show("You have entered all the amino acids for this protein", "Attention",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
Reset_Click(sender, e);
}
TNX for the help!
I'm not sure if having two select statements in your MySQL query is valid or not, or why you're taking a string only to turn it into a number so you can add it to another string, but this is probably the cause of the syntax error.
" SELECT COUNT(tblOrderAA.orderAASerialPro) AS orderAASerialPro1 FROM tblOrderAA" +
"WHERE tblOrderAA.orderAASerialPro=" + Convert.ToInt32(serialPro.Text) +
The way you're concatenating this string means there would be no space between tblOrderAA and WHERE. Add a space in between.
You should also look up SQL injection/parameterized queries.
First, the way you have it setup, even if it were supported by access, would require you to process different resultset (you would have to call Reader.NextResult in order to get the values from the second select statement.
However, this is an easy problem to solve: break your queries up into separate commands and just get the one value from each query that you are looking for:
int TotalCompleted;
int TotalToComplete;
string mySQL;
OleDbCommand datacommand;
object oValue;
mySQL = " SELECT COUNT(tblOrderAA.orderAASerialPro) AS orderAASerialPro1 FROM tblOrderAA WHERE tblOrderAA.orderAASerialPro=" + Convert.ToInt32(serialPro.Text);
datacommand = new OleDbCommand(mySQL, myConnection);
oValue = datacommand.ExecuteScalar();
if (oValue != DBNull.Value)
{
TotalCompleted = (int)oValue;
} else
{
TotalCompleted = 0;
}
mySQL = "SELECT tblProInfo.proInfoSerialNum FROM tblProInfo WHERE tblProInfo.proInfoSerialNum=" + Convert.ToInt32(serialPro.Text);
datacommand = new OleDbCommand(mySQL, myConnection);
oValue = datacommand.ExecuteScalar();
if (oValue != DBNull.Value)
{
TotalToComplete = (int)oValue;
} else
{
TotalToComplete = 0;
}
if (TotalCompleted == TotalToComplete)
{
MessageBox.Show("You have entered all the amino acids for this protein", "Attention",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation,
MessageBoxDefaultButton.Button1);
Reset_Click(sender, e);
}

Categories