I have the following method that sets an object to a specific status (it sets a column value of a specific row to '4' :
C#
void setObjectToFour(int objectID)
{
using (var conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["Database"].ConnectionString))
using (var command = new SqlCommand("setObjectToFour", conn)
{
CommandType = CommandType.StoredProcedure
})
{
command.Parameters.Add(new SqlParameter("#objectID", SqlDbType.Int)).Value = objectID;
conn.Open();
command.ExecuteNonQuery();
}
}
SQL:
...
AS
BEGIN
Update [DB_OBJECT].[dbo].[object_table]
SET status = 4
WHERE id = #objectID
END
The problem is that the DB_OBJECT DB is not managed by us and is the DB of a piece of software.
The followed problem is that the query from above not always works (and we haven't figured out why) and I were thinking about how we could 'force' or 'check' if the row was updated.
Is it smart to do it as follow?:
1 - Create new C# Method Check and stored procedure getStatus that retrieves the status of the object
2 - I will put both methods from above in a do while until the status is 4.
Is this a smart approach?
ExecuteNonQuery() method returns the number of rows affected.
int recordAffectd = command.ExecuteNonQuery();
if (recordAffectd > 0)
{
// do something here
}
ExecuteNonQuery() does not return data at all: only the number of rows affected by an insert, update, or delete.
try this
if (command.ExecuteNonQuery() != 0)
{
// more code
}
Related
For some reason, ExecuteNonQuery() in C# returns -1, though when I run a query separately, the value returns the actual value needed.
For Example:
try
{
var connString ="Data Source=ServerName;InitialCatalog=DatabaseName;Integrated Security=true;"
SqlConnection conn = new SqlConnection(connString);
SqlCommand someCmd = new SqlCommand("SELECT COUNT(*) FROM SomeTable");
someCmd.Connection = conn;
conn.Open();
var theCount = cmd.ExecuteNonQuery();
conn.Close();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
When the command is executed it returns -1. Though if run the query separately,
SELECT COUNT(*) FROM SomeTable;
Column returns one row with a count of 4 if that table being queried has 4 rows.
Based on MSDN:
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command. When a trigger exists on a table being inserted or updated, the return value includes the number of rows affected by both the insert or update operation and the number of rows affected by the trigger or triggers. For all other types of statements, the return value is -1. If a rollback occurs, the return value is also -1.
You want to return the number of rows affected by the command and save it to an int variable but since the type of statement is select so it returns -1.
Solution: If you want to get the number of rows affected by the SELECT command and save it to an int variable you can use ExecuteScalar.
var theCount = (int)cmd.ExecuteScalar();
You can use Ef core with Ado.net like this example
var context = new SampleDbContext();
using (var connection = context.Database.GetDbConnection())
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = "SELECT COUNT(*) FROM SomeTable";
var result = command.ExecuteScalar().ToString();
}
}
I have a stored procedure that returns 0 or 1 depending on certain outcomes. I often execute this procedure manually, so to have a description of the success/failure that's easily viewed in SSMS but still readable as 0/1 in code, I select the 0 or 1 as a different column name, i.e. SELECT 0 AS ThisReason or SELECT 0 AS ThatReason.
There is almost certainly a better way to handle this, but it got me curious - is it possible to read the name of the column you've selected when using ExecuteScalar in C#?
Not with ExecuteScalar but with ExecuteReader and SqlDataReader.GetName:
using (var con = new SqlConnection("connection-string"))
using (var cmd = new SqlCommand("storedprocedurename", con))
{
cmd.CommandType = CommandType.StoredProcedure;
// parameters here...
con.Open();
using (var rd = cmd.ExecuteReader())
{
if (rd.Read())
{
string column = rd.GetName(0); // first column
int value = rd.GetInt16(0); // or rd.GetInt32(0)
}
}
}
What you want to do is to get two bits of information as a result of a query. To use ExecuteScalar you will need to first "pack" those two bits into one. For example you could return a string starting with "+" or "-" indicating the success/failure, and the rest of the string could be a "reason".
There is no other way to do this with ExecuteScalar.
I am updating a row in SQL DB using the code below. The loop works and it updates the row but the problem is that each time it goes through the loop, it only updates one value and the other values are overwritten. So at the end, it has updated but instead of multiple values being inputted to the table for the respective Project ID, it only puts one value for the respective Project ID. I am not receiving any errors for this. Any help is much appreciated.
for (int i = 0; i < cbAvailableEntities.Items.Count - 1; i++)
{
SqlConnection connection = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand("UpdateProjectEntity", connection);
using (connection)
{
connection.Open();
using (cmd)
{
if (cbAvailableEntities.Items[i].Selected)
{
cmd.CommandType = CommandType.StoredProcedure;
//the following is the Project ID for the row being updated.
SqlParameter paramPID = new SqlParameter("#ProjectID", nr.ProjectID);
cmd.Parameters.Add(paramPID);
nr.Entities = cbAvailableEntities.Items[i].Value;
cmd.Parameters.AddWithValue("#CorpID", nr.Entities);
cmd.ExecuteNonQuery();
}
}
}
}
Here is the SQL query for the Stored Procedure "UpdateProjectEntity"
ALTER PROCEDURE [dbo].[UpdateProjectEntity]
#ProjectID int,
#CorpID int
AS
BEGIN
UPDATE [dbo].[ProjectEntity]
SET
[CorpID] = #CorpID
WHERE
ProjectID = #ProjectID
END
Here are screenshots of inputs and results when I run the program.
These are the checkboxes I am saving to the DB
This is the result after I have saved to the DB
I changed the date to show that everything else works in this program.
I can see you save your enity INT, maybe you should save it as a Comma Separated String.
So instead of save 1, you can save 1,2,3
Of course you will have to add some logic before the save building and concat the string. And also need to do some parsing when you read from db doing the split by ,
The other aproach is creating a relation table to indicate with are the options selected.
But this is also have problem when you remove a selection and add new ones.
ProjectID CorpID
1 1
1 2
1 3
The way I resolved this without making any changes to the DB is I used a DELETE Statement to delete the rows with the ProjectID and then I used an insert stored procedure that I have used before. It was a lot faster than creating another table among all that is already in place. So the code looks like this
for (int i = 0; i < cbAvailableEntities.Items.Count - 1; i++) {
SqlConnection connection = new SqlConnection(connString);
SqlCommand com = new SqlCommand("InsertProjectEntity", connection);
SqlCommand dcm = new SqlCommand();
using(connection) {
//First time going through the loop, i = 0 is true.
if (i == 0) {
connection.Open();
using(com) {
//This will remove anything in the DB related to the ProjectID being edited.
dcm.Connection = connection;
dcm.CommandText = "DELETE FROM [dbo].[ProjectEntity] WHERE ProjectID = " + _pID;
dcm.ExecuteNonQuery();
//This will insert all items checked in the checkboxlist but will not insert the unchecked.
if (cbAvailableEntities.Items[i].Selected) {
com.CommandType = CommandType.StoredProcedure;
SqlParameter paramPID = new SqlParameter("#ProjectID", nr.ProjectID);
com.Parameters.Add(paramPID);
nr.Entities = cbAvailableEntities.Items[i].Value;
com.Parameters.AddWithValue("#CorpID", nr.Entities);
com.ExecuteNonQuery();
}
}
} else {
connection.Open();
using(com) {
//This will insert all items checked in the checkboxlist but will not insert the unchecked.
if (cbAvailableEntities.Items[i].Selected) {
com.CommandType = CommandType.StoredProcedure;
SqlParameter paramPID = new SqlParameter("#ProjectID", nr.ProjectID);
com.Parameters.Add(paramPID);
nr.Entities = cbAvailableEntities.Items[i].Value;
com.Parameters.AddWithValue("#CorpID", nr.Entities);
com.ExecuteNonQuery();
}
}
}
}
Here's my code
// SqlCommand query = new SqlCommand("INSERT INTO devis (idProposition, identreprise, tauxHoraire, fraisGenerauxMO, fraisGenerauxPiece, beneficeEtAleas, idStatut, prixUnitaireVenteMO ) VALUES(#idproposition, #identreprise, #tauxHoraire, #fraisGenerauxMO, #fraisGenerauxPiece, #beneficeEtAleas, 1, #prixUnitaireVenteMO) ", Tools.GetConnection());
SqlCommand query = new SqlCommand("INSERT INTO devis (idProposition, identreprise, tauxHoraire, fraisGenerauxMO, fraisGenerauxPiece, beneficeEtAleas, idStatut, prixUnitaireVenteMO, alerteEntrepriseEnvoyee,fraisDeplacement ) VALUES(1051, 85, 20, 2, 2, 2.2, 1, 88,0,-1) ", Tools.GetConnection());
//query.Parameters.AddWithValue("idproposition", this.ID);
//query.Parameters.AddWithValue("identreprise", competitor.ID);
//query.Parameters.AddWithValue("tauxHoraire", competitor.CoefTauxHoraire);
//query.Parameters.AddWithValue("fraisGenerauxMO", competitor.CoefFraisGenerauxMO);
//query.Parameters.AddWithValue("fraisGenerauxPiece", competitor.CoefFraisGenerauxPiece);
//query.Parameters.AddWithValue("beneficeEtAleas", competitor.CoefBeneficeEtAleas);
//query.Parameters.AddWithValue("prixUnitaireVenteMO", Math.Round(competitor.CoefTauxHoraire * competitor.CoefFraisGenerauxMO * competitor.CoefBeneficeEtAleas, 2));
bool insertOK = (query.ExecuteNonQuery() == 1);
if (insertOK)
{
// DO SOMETHING
}
insertOk is false but in the database the row is inserted with all the information that I specified
I rebuilt the query manually to see if the problem came from the query.Parameters, it inserts without error again into the database but insertOk is still false! I even added two other fields which aren't supposed to be null but the activity is the same in both cases
any ideas?
ExecuteNonQuery it claims to return The number of rows affected.. This is incorrect, as there is no way for the client to know the number of rows affected. The documentation incorrectly assumes that the engine will report the number of rows affected, but that is subject to the session SET NOCOUNT state. Do not write code that assumes the NOCOUNT is always on. If you need to know the number of rows affected use the OUTPUT clause. Relying on the ##ROWCOUNT or the SET NOCOUNT state is subject to many many corner cases where the value is incorrect from one point of view or another.
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command.
When a trigger exists on a table being inserted or updated, the return value includes the number of rows affected by both the insert or update operation and the number of rows affected by the trigger or triggers. For all other types of statements, the return value is -1. If a rollback occurs, the return value is also -1.
ExecuteNonQuery method returns System.Int32
Executes a Transact-SQL statement against the connection and returns
the number of rows affected.
Return Value
Type: System.Int32
The number of rows affected.
Since your query.ExecuteNonQuery() returns 2, it is too obvious 2 == 1 returns false.
Your query will be;
bool insertOK = (2 == 1);
DEMO.
Try using SqlDataAdapter such that :
SqlDataAdapter Adabter = new SqlDataAdapter();
Adabter.InsertCommand = new SqlCommand("INSERT INTO devis values(#idProposition, #identreprise), Tools.GetConnection());
Adabter.InsertCommand.Parameters.Add("#idproposition",SqlDbType.Int).Value = yorID;
Adabter.InsertCommand.Parameters.Add("#identreprise", SqlDbType.Int).Value = yorID;
Tools.OpenConnection();
int result = Adabter.InsertCommand.ExecuteNonQuery();
Tools.CloseConnection();
if( result > 0 )
{
MessageBox.Show("Information Added");
}else
{
MessageBox.Show("Error");
}
Same issue here with an UPDATE query. In my case I had to add "set nocount off" to the SQL. Example code:
string sql =
$#"set nocount off;update PRODUCT_PLAN
set WORKING_STATUS = 'P',
user_id = #USER_ID
where workorder_base_id = #BASE_ID
";
SqlCommand cmd = new SqlCommand();
cmd.Connection = connection;
cmd.CommandType =CommandType.Text;
cmd.Parameters.AddWithValue("#USER_ID", opl.USER_ID);
cmd.Parameters.AddWithValue("#BASE_ID", opl.WORKORDER_BASE_ID);
cmd.CommandText = sql;
// Nr of rows updated in retval
int retval = cmd.ExecuteNonQuery();
I am trying to write a common Save function and I am using Dbcommand. My code is:
private static int Save(CommandType commandtype, string commandText, SqlParameter[] commandParameters, bool p)
{
int id = -1;
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
using (DbCommand command = factory.CreateCommand())
{
command.Connection = connection;
command.CommandType = commandtype;
command.CommandText = commandText;
foreach(SqlParameter pa in commandParameters)
{
command.Parameters.Add(pa);
}
connection.Open();
id = command.ExecuteNonQuery();
}
}
return id;
}
Where am I going wrong? The code saves the value in the database.
Please delete the line in the SP SET NOCOUNT ON; in the SP so you will get
the value
ExecuteNonQuery returns the number of rows affected.
If your SQL statement is something like
insert into ... values ...
select ##identity
Then you need to use ExecuteScalar instead.
For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command. When a trigger exists on a table being inserted or updated, the return value includes the number of rows affected by both the insert or update operation and the number of rows affected by the trigger or triggers. For all other types of statements, the return value is -1. If a rollback occurs, the return value is also -1.
look at msdn
But I don't understand what do you mean when you said that the method ExecuteNonQuery should return value.
If you want to return a value you should use the ExecuteScalar
Execute Scalar returns only 1 row..and executenonquety returns affected rows only...
ExecuteNonQuery doesnt give u return values...