I am trying to see if this cell in my excel spreadsheet is the PK in the database. I am using Aspose for bring in the excel file (this works). I know the connection string is working as well.
I am wanting to query the database for this code. If this code brings a row back, I want the flag to be true. If no rows come back, I want to move on since the flag is already set to false. I tried it and I keep getting true ever though that code isn't in the database. Can someone help me to get this working properly? Or is there a simpler way to get this task achieved?
#region StateCharges_Status
public static bool StateCharges_Status(DataRow dr) {
bool ok = StateCharges_Exists(dr);
if (ok)
return StateCharges_Update(dr);
else
return StateCharges_Insert(dr);
}
#endregion
#region StateCharges_Exists
private static bool StateCharges_Exists(DataRow dr) {
bool flag = false;
Database pbkDB = DatabaseFactory.CreateDatabase("PbKConnectionString");
DbCommand dbCommand = pbkDB.GetSqlStringCommand(string.Format(#"Select * from tblCtStateCharges where code = '{0}'", dr["Code"].ToString()));
try {
pbkDB.ExecuteNonQuery(dbCommand);
flag = true; // <-- I guess this is where it needs something added.
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
return flag;
}
#endregion
You should change the query to something like:
DbCommand dbCommand = pbkDB.GetSqlStringCommand(string.Format(#"Select count(*) as cnt from tblCtStateCharges where code = '{0}'", dr["Code"].ToString()));
There is no need to select every field when you only care if the record exists.
Then you change the
pbkDB.ExecuteNonQuery(dbCommand);
to something like
int count = (int)pbkDB.ExecuteScalar(dbCommand);
Then change the setting of flag to (you won't need the if anymore)
flag = count > 0;
So the new code would look something like
private static bool StateCharges_Exists(DataRow dr) {
bool flag = false;
Database pbkDB = DatabaseFactory.CreateDatabase("PbKConnectionString");
DbCommand dbCommand = pbkDB.GetSqlStringCommand(string.Format(#"Select count(*) as cnt from tblCtStateCharges where code = '{0}'", dr["Code"].ToString()));
try {
int count = (int)pbkDB.ExecuteScalar(dbCommand);
flag = count > 0;
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
return flag;
}
you should use the ExecuteQuery-method which returns a IEnumerable.
then you can test for result by writing:
var result = pbkDB.ExecuteQuery(dbCommand);
flag = result.Count() > 0;
Related
I have a discord bot that gets its data from a SQLite Database. I am using the System.Data.SQLite-Namespace
My problem is this code part:
m_dbConnection.Open();
SQLiteDataReader sqlite_datareader;
SQLiteCommand sqlite_cmd;
sqlite_cmd = m_dbConnection.CreateCommand();
sqlite_cmd.CommandText = SQLCommand; //SQLCommand is a command parameter
sqlite_datareader = sqlite_cmd.ExecuteReader();
while (sqlite_datareader.Read())
{
int i = 0;
while (true)
{
try
{
string temp = "";
try
{
temp = sqlite_datareader.GetString(i).ToString();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
try
{
temp = sqlite_datareader.GetInt32(i).ToString();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
break;
}
}
output.Add(temp);
i++;
}
catch (Exception)
{
break;
}
}
}
For this example the variable SQLCommand is "SELECT Money FROM Users WHERE UserId = 12345 AND ServerID = 54321".
When I execute this command in an SQL Editor, , I get the value "10". So the command works. Now when I pass this command in my method, to get the data, I just got with the editor, I get the error Specified cast is not valid. at the code temp = sqlite_datareader.GetString(i).ToString();.
The value i is 0, to get the very first row that the sql command selected. I don't know why this happens, every other SQLite-Command works and gives me what I want. Why isn't this command working too?
Try using it this way
while (sqlite_datareader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
var ColName = reader.GetName(i);
var colValue = reader[i];
}
}
Please note that
while (sqlite_datareader.Read()){..}
the purpose of the above statement is to fetch all the rows.
therefore I would like to mention the problems in your code
1-) while(true){...}
is infinite loop, ofcourse in this scenario it would hit the break and quit but still this is not a good practice
2-) int i = 0;
you have declared and increased it by one inside the while loop. The problem here is that:
say you have 100 rows and 10 columns; this means that i would be increased to 99
however you have 10 colums, trying to get an invalid column value would give you an error
putting your code in try catch/ nested try catch statements would solve the issue however it's a nasty solution.
I am using MySql 5.6x with Visual Studio 2015, windows 10, 64-bit. C# as programming language. In my CRUD.cs (Class file) i have created the following method:
public bool dbQuery(string sql,string[] paramList= null)
{
bool flag = false;
try
{
connect();
cmd = new MySqlCommand(sql,con);
cmd.Prepare();
if(paramList != null){
foreach(string i in paramList){
string[] valus = i.Split(',');
string p = valus[0];
string v = valus[1];
cmd.Parameters[p].Value = v;
}
}
if (cmd.ExecuteNonQuery() > 0)
{
flag = true;
}
}
catch (Exception exc)
{
error(exc);
}
}
I am passing the query and Parameters List like this:
protected void loginBtn_Click(object sender, EventArgs e)
{
string sql = "SELECT * FROM dept_login WHERE (user_email = ?user_email OR user_cell = ?user_cell) AND userkey = ?userkey";
string[] param = new string[] {
"?user_email,"+ userid.Text.ToString(),
"?user_cell,"+ userid.Text.ToString(),
"?userkey,"+ userkey.Text.ToString()
};
if (db.dbQuery(sql, param))
{
msg.Text = "Ok";
}
else
{
msg.Text = "<strong class='text-danger'>Authentication Failed</strong>";
}
}
Now the problem is that after the loop iteration complete, it directly jumps to the catch() Block and generate an Exception that:
Parameter '?user_email' not found in the collection.
Am i doing this correct to send params like that? is there any other way to do the same?
Thanks
EDIT: I think the best way might be the two-dimensional array to collect the parameters and their values and loop then within the method to fetch the parameters in cmd.AddWidthValues()? I may be wrong...
In your dbQuery you don't create the parameters collection with the expected names, so you get the error when you try to set a value for a parameter that doesn't exist
public bool dbQuery(string sql,string[] paramList= null)
{
bool flag = false;
try
{
connect();
cmd = new MySqlCommand(sql,con);
cmd.Prepare();
if(paramList != null){
foreach(string i in paramList){
string[] valus = i.Split(',');
string p = valus[0];
string v = valus[1];
cmd.Parameters.AddWithValue(p, v);
}
}
if (cmd.ExecuteNonQuery() > 0)
flag = true;
}
catch (Exception exc)
{
error(exc);
}
}
Of course this will add every parameter with a datatype equals to a string and thus is very prone to errors if your datatable columns are not of string type
A better approach would be this one
List<MySqlParameter> parameters = new List<MySqlParameter>()
{
{new MySqlParameter()
{
ParameterName = "?user_mail",
MySqlDbType= MySqlDbType.VarChar,
Value = userid.Text
},
{new MySqlParameter()
{
ParameterName = "?user_cell",
MySqlDbType= MySqlDbType.VarChar,
Value = userid.Text
},
{new MySqlParameter()
{
ParameterName = "?userkey",
MySqlDbType = MySqlDbType.VarChar,
Value = userkey.Text
},
}
if (db.dbQuery(sql, parameters))
....
and in dbQuery receive the list adding it to the parameters collection
public bool dbQuery(string sql, List<MySqlParameter> paramList= null)
{
bool flag = false;
try
{
connect();
cmd = new MySqlCommand(sql,con);
cmd.Prepare();
if(paramList != null)
cmd.Parameters.AddRange(paramList.ToArray());
if (cmd.ExecuteNonQuery() > 0)
{
flag = true;
}
}
catch (Exception exc)
{
error(exc);
}
}
By the way, unrelated to your actual problem, but your code doesn't seem to close and dispose the connection. This will lead to very nasty problems to diagnose and fix. Try to use the using statement and avoid a global connection variable
EDIT
As you have noticed the ExecuteNonQuery doesn't work with a SELECT statement, you need to use ExecuteReader and check if you get some return value
using(MySqlDataReader reader = cmd.ExecuteReader())
{
flag = reader.HasRows;
}
This, of course, means that you will get troubles when you want to insert, update or delete record where instead you need the ExecuteNonQuery. Creating a general purpose function to handle different kind of query is very difficult and doesn't worth the work and debug required. Better use some kind of well know ORM software like EntityFramework or Dapper.
Your SQL Commands' Parameters collection does not contain those parameters, so you cannot index them in this manner:
cmd.Parameters[p].Value = v;
You need to add them to the Commands' Parameters collection in this manner: cmd.Parameters.AddWithValue(p, v);.
I'm trying to check if a username exists in my table when everytime a character is entered in the TextBox. Here is my code:
Within the register.aspx.cs file I have a TextChanged event on the TextBox:
protected void username_txt_TextChanged(object sender, EventArgs e)
{
string check = authentication.checkUsername(username_txt.Text);
if(check == "false")
{
username_lbl.Text = "Available";
}
else
{
username_lbl.Text = "Not Available";
}
}
It calls this method:
public static string checkUsername(string Username)
{
userInfoTableAdapters.usersTableAdapter userInfoTableAdapters = new userInfoTableAdapters.usersTableAdapter();
DataTable userDataTable = userInfoTableAdapters.checkUsername(Username);
DataRow row = userDataTable.Rows[0];
int rowValue = System.Convert.ToInt16(row["Users"]);
if (rowValue == 0)
{
return "false";
}
else
{
return "true";
}
}
The query that is being executed is:
SELECT COUNT(username) AS Users FROM users WHERE (username = #Username)
For some reason, it keeps breaking on this line:
DataTable userDataTable = userInfoTableAdapters.checkUsername(Username);
It gives an error that says:
Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.
Just incase, the username field in my table is Unique and Not Null, I have tried just executing the query itself and it works perfectly so it isn't at the query end.
Does anyone understand what I am doing wrong?
Your query doesn't return the row - so using a TableAdapter query that returns the DataTable is inappropriate in this case.
I'd recommend using your query with something like the function below. I took the liberty of actually returning boolean....
public static bool checkUsername(string userName)
{
SqlClient.SqlCommand withCmd = new SqlClient.SqlCommand();
bool result = false;
withCmd.Connection.Open();
withCmd.CommandType = CommandType.text;
withCmd.CommandText = "SELECT COUNT(username) AS Users FROM users WHERE (username = #Username)"
withCmd.Parameters.Add(new System.Data.SqlClient.SqlParameter("#Username", System.Data.SqlDbType.VarChar, 16)).Value = userName;
try {
int intResult;
object scalarResult = withCmd.ExecuteScalar();
if ((scalarResult != DBNull.Value)
&& (scalarResult != null)
&& (int.TryParse(scalarResult, out intResult)))
result = (intResult==1);
} catch (Exception ex) {
result = false; // hmm, bad...can't tell handle error...
} finally {
// only close if we opened the connection above ...
withCmd.Connection.Close();
}
}
return result;
}
A TableAdapter does support scalar queries on the Table Object, when you add and name your query, check the properties of that query and be sure its ExecuteMode is Scalar. It will then return the integer value, not the row!
On the other hand, if you want to keep your structure, change the query to actually return the row, something like
SELECT uu.* AS dbo.Users uu FROM users WHERE (username = #Username)
and make the result of the checkUsername() function depend on the number of rows returned (which should be 1 or zero....)
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 got a typed dataset in my form. Using BindingSource to walk in rows, inserting and updating records.
Everything is fine but I need inserted records identity value for generating a string for my GeneratedCode field in my table.
After getting this value I'll send value to my CodeGen() method and generate string, and update same row's CodeGen field with this value.
I'm using Access database. I know there is that ##Identity thing for Access, but how can I use it? I don't want to use OleDbCommand or something like this.
How can I do that?
string GenCode(int pCariId)
{
string myvalue;
int totalDigit = 7;
myvalue = "CR" + pCariId.ToString();
for (int digit = myvalue.Length; digit <= totalDigit - 1; digit++)
{
myvalue = myvalue.Insert(2, "0");
}
return myvalue;
}
private void dataNavigator_ButtonClick(object sender, NavigatorButtonClickEventArgs e)
{
switch (e.Button.ButtonType)
{
case NavigatorButtonType.EndEdit:
try
{
this.Validate();
if (KaydetFlags == 1)
{
this.bndCariKayit.EndEdit();
datagate_muhasebeDataSet.TB_CARI.Rows[datagate_muhasebeDataSet.Tables["TB_CARI"].Rows.Count - 1]["INS_USR"] = 0;
datagate_muhasebeDataSet.TB_CARI.Rows[datagate_muhasebeDataSet.Tables["TB_CARI"].Rows.Count - 1]["INS_TRH"] = DateTime.Now;
XtraMessageBox.Show("Yeni Cari Kaydı Tamamlandı.");
KaydetFlags = 0;
}
else
{
DataRowView currentRow = (DataRowView)bndCariKayit.Current;
currentRow.Row["UPD_USR"] = "0";
currentRow.Row["UPD_TRH"] = DateTime.Now;
XtraMessageBox.Show("Cari Kaydı Güncellendi.");
this.bndCariKayit.EndEdit();
}
this.tB_CARITableAdapter.Update(datagate_muhasebeDataSet.TB_CARI);
}
catch (System.Exception ex)
{
XtraMessageBox.Show("Kayıt İşlemi Başarısız. Lütfen Tekrar Deneyiniz.");
}
break;
According to documentation you have to use RowUpdated method of your TableAdapter
private static void OnRowUpdated(
object sender, OleDbRowUpdatedEventArgs e)
{
// Conditionally execute this code block on inserts only.
if (e.StatementType == StatementType.Insert)
{
OleDbCommand cmdNewID = new OleDbCommand("SELECT ##IDENTITY",
connection);
// Retrieve the Autonumber and store it in the CategoryID column.
e.Row["CategoryID"] = (int)cmdNewID.ExecuteScalar();
e.Status = UpdateStatus.SkipCurrentRow;
}
}
Another option, which I actually use is to create Select query which simply gets maximum value from you id column:
SelectLastAddedId:
SELECT MAX(id) FROM obmiar
Just set query execute mode to scalar and you can refer to it in your code as
int lastId = TableAdapter.SelectLastAddedId()