Stored procedure executes but does not update data - c#

I have a stored procedure in a SQL Server 2005 database that's accessed by ASP.NET / C# code.
The parameters for the stored procedure are defined in the typical manner:
Try
{
SqlCommand cmd = new SqlCommand("mystoredprocedure",myConnection)
cmd.Parameters.Add(new SqlParameter("#p1"), SqlDbType.Int))
cmd.Parameters["#p1"].Value = myvalue (usually form inputs)
.
.
.
myConnection.Open()
cmd.ExecuteNonQuery()
}
catch (Exception xx)
{
lblError.Text = xx.Message;
}
finally
{
myConnection.Close();
}
The problem is my data never updates, though the stored procedure doesn't throw any errors. I've checked the procedure in SQL Server, and when I call it directly through SQL Server the proc makes my updates.
I'm tearing my hair out on this one since it worked fine for a long time, then stopped working. I've checked the usual culprits (db connection is pointing to the right database, the procedure seems to work fine in SQL Server, and I've commented out the few new parameters I've created)
Any thoughts on what could be causing this? It's strange that the same procedure works in SQL Server but not through my code without throwing any errors. (To be sure, I put a return value in the stored procedure, and the return value indicates I'm not rolling back)
EDIT
Code for the stored procedure:
BEGIN TRANSACTION
--get count
update dbo.myTable set
val1=#val1,
val2=#val2,
.
.
.
WHERE ID=#MyID
SET #Err = ##ERROR
--if error rollback transaction
IF #Err <> 0
BEGIN
ROLLBACK TRANSACTION
GOTO ErrorHandler
END
Select #ReturnCode = 1
COMMIT TRANSACTION
RETURN
ErrorHandler:
--unknown error
Select #ReturnCode = 0
RAISERROR (#Err, 16, 1 ) WITH LOG
RETURN -100
EDIT
When I parse cmd.ExecuteNonQuery, I get -1 as a result. Still trying to figure out why the C# code is doing this but not throwing any errors. Shouldn't ExecuteNonQuery return the number of rows affected by the stored procedure?
EDIT
Using TFS I've stepped back in my history a couple of revs - it seems like there's an additional field I added recently that's breaking the query. When I comment out that field and call my sproc, it works fine.
I don't get why, though - it's just a varchar(255) field. I've got plenty of other fields in this database that are set up in similar ways. Any thoughts as to why this would be a problem?
EDIT
Using SQL Profiler, I can see the statement execute AND commit...but still, no data updates. I'm wondering whether I need to trash the sproc and start over again?

Run the stored procedure without the .Net code (i.e directly in SQL Server Management Studio) and see whether the changes are updated or not. Probably you are missing an explicit commit statement.

May sound stupid, but if you are out of disk space I've seen SQL server go through the motions, no errors but your data does not get saved. Easy to check too!

Try to set CommandType like that :
SqlCommand cmd = new SqlCommand("mystoredprocedure",myConnection)
cmd.CommandType = CommandType.StoredProcedure

Try to use:
SqlCommand cmd;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
or you maybe use:
CALL mystoredprocedure(#ParameterName)
as SQL-Text

try this !
SqlCommand cmd = new SqlCommand(string.Format("mystoredprocedure('{0}')",inputValue),myConnection)

Try to run sp directly from SQL SERVER and remove error handling from stored procedure to get the exact error in .Net.

Can you try one simple thing for me?
Change your stored procedure to accept no parameter. Change logic of stored proc to just insert one row in one table and then change your code to call that procedure and find out whether call is successful or not.

I think that you use a wrong way to call a stored procedure. The value -1 returned by ExecuteNonQuery is because of the statement: if INSERT/UPDATE/DELETE the value is the number of rows affected, -1 if there's a rollback. In all the other cases the return value is -1 (your case, I think).
The SqlCommand constructor when used with the two parameters SqlCommand(String, SqlConnection) needs that the first one is a generic query so you can run something like "exec myProcedure #par1" and the parameters can be set e.g.:
Dim par1 As New SqlParameter("#par1", SqlDbType.VarChar, 50)
par1.Value = "DummyValue"
cmd.Parameters.Add(par1)
But in the ideal situation, when you've to call a stored than you've to set the CommandType to "StoredProcedure", like then MSDN suggests in this link http://msdn.microsoft.com/it-it/library/yy6y35y8.aspx.
(I will show you VB code... sorry.. it's easily converted to C# with tools like this.)
If you want to read a value from the stored procedure that you run, you can populate a datased (for example, "ds") using a SqlAdapter -this is only an example-:
Dim da As New SqlDataAdapter(cmd)
da.Fill(ds, "result")
If ds.Tables.Item("result").Rows.Count > 0 Then
Return True
Else
Return False
End If
If you don't need to read anything you can simply use:
cmd.ExecuteNonQuery()
Surely you've to tell that you want to launch a stored procedure:
cmd.CommandType = CommandType.StoredProcedure
Hope to be useful to you...
Bye, Massimo.

I think you are missing Command Type while creating Command object.. Set command type of command object as StoreProcegure and then check again.. Since if u dont set command type then ur query execute but u wont get any error and required result also.

From your code I can see that the parameter name you are passing is not the same that you are using in you procedure.

Related

SQL Stored Procedure error by updating

Im trying to use a stored procedure with parameter, in this case the OrderID.
But i'm getting the error : 'Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32).'
My C# methode:
using (SqlCommand cmd = new SqlCommand("UpdateStock", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#OrderID", SqlDbType.Int).Value = OrderId;
cmd.ExecuteNonQuery();
}
My Stored Procedure:
CREATE PROCEDURE [dbo].[UpdateStock] #OrderID int
AS
BEGIN
UPDATE Products SET Stock = Stock -1 FROM Products INNER JOIN
OrderDetails ON
Products.ProductId = OrderDetails.ProductID WHERE OrderDetails.OrderID =
#OrderID
END
GO
Maybe you guys can help me out?
Looking at the code you provided so far looks fine. However the error is saying something like - somewhere, a stored procedure is calling another stored procedure and then again and again.. too many times. It could also mean that there is 1 stored procedure calling itself too many times.
So the provided code doesn't show this behavior so I would suggest looking elsewhere. As mentioned in the comments a good place to look are the triggers on the Products table. A trigger might run when you try to update it which could be the root of the problem.

Understanding ExecuteNonQuery's return value

First, just to be clear, I recognize that ExecuteNonQuery should only be used for UPDATE, INSERT, or DELETE statements, and that for all other types of statements, such as SELECT, the return value is -1.
My question is, why does the following stored procedure:
CREATE PROCEDURE `ExampleProc`(IN Name varchar(60), OUT ID bigint(20), OUT SP varchar(255))
BEGIN
SELECT id, sp INTO ID, SP FROM users WHERE username = Name;
END
When executed using ExecuteNonQuery:
using (var conn = new MySqlConnection("Secret"))
{
conn.Open();
using (var cmd = new MySqlCommand("ExampleProc", conn) { CommandType = CommandType.StoredProcedure })
{
cmd.Parameters.AddWithValue("Name", request.Name).MySqlDbType = MySqlDbType.VarChar;
cmd.Parameters.Add("ID", MySqlDbType.Int64).Direction = ParameterDirection.Output;
cmd.Parameters.Add("SP", MySqlDbType.VarChar).Direction = ParameterDirection.Output;
var returnVal = cmd.ExecuteNonQuery();
}
}
Yield a 0 in returnVal when a row with Name is not found, and a 1 if it is found? Based on all the documentation I have read, since the stored procedure contains a single SELECT statement, I should be seeing -1 being returned no matter what. Instead, it's returning the number of rows affected/found, which doesn't make sense according to the documentation.
Lastly, I've also tried using just "SELECT *" instead of "SELECT id, sp INTO ID, SP". That seems to always return 0. Still not the -1 that I am expecting.
Let's understand the working of the ExecuteNonQuery API in the ADO.Net, as you have understood from the documentation that it shall provide the number of Rows impacted as part of DML query and -1 for the Select query.
However the internal working is such that in case of Sql Server, default setting is Set NoCount Off helps in writing to the TDS protocol, the number of modified rows and same is read by the Ado.Net APIs, thus the correct result, this is the result of native binary integration of ado.net with Sql Server. more details at the following links:
Ado.Net TDS Protocol
SET NOCOUNT ON usage
When it comes to other database, like MySql, Oracle, there's no guarantee of the same behavior, as their integration is not at same level as Sql Server. This is the main reason for discrepancy, posted in the question, to make it consistent across the database, you may want to rely of a Output Parameter to automatically fill the value internally in the procedure, since every database has mechanism to figure out the number of rows updated

Call to SQL Server stored procedure failing in certain cases

I am struggling to understand why a certain stored procedure has stopped working in a few of my databases, but not in others. I am hoping that someone can help me resolve this issue.
Introduction
I inherited an existing C# application that connects to a choice of SQL Server databases depending on the culture parameter supplied to the program. Example: Passing "en-CA" causes the program to connect to the database with English-Canada content. Passing "fr-CA" causes the program to connect to the database with French-Canada content. The databases are derived from a common root database. The databases are essentially identical except for the contents of many of the NVARCHAR fields. (This variety of databases is used solely during development for testing various cultures.)
Both databases use the following collation: SQL_Latin1_General_CP1_CI_AS
Issue
I am not sure when this issue started, but the current situation is that if I call a certain stored procedure from the fr-CA database, then it is not executed at all. (I will explain this in more detail.) No error code is returned to the program. the program acts as if no record was found.
However, if I call the same stored procedure from the en-CA database, then it functions as expected and a record is returned to the program.
Attempted Steps
If I run the stored procedure from SSMS, then it executes properly.
I have attempted copying the definition of the stored procedure from the database where it is executing properly to the database where it is not executing properly. This did not resolve the issue.
I did try debugging with the SQL Profiler. When I ran the stored procedure against both databases, I see an entry in the trace. I do not see any errors listed. I will admit that I am a newbie when it comes to using the Profiler.
When I say that the stored procedure is not being executed, I base this on the following test. I created a debug table with a couple of fields:
create table DEBUG
(
Id INTEGER,
Line NVARCHAR(100)
);
At the top of the stored procedure, in both databases, I inserted as the very first line the following statement:
INSERT INTO dbo.DEBUG VALUES (1, 'Top of Atms_Get_Tray_Infos');
When my code calls the stored procedure, I expect to see a line in the DEBUG table.
If I run the program against the en-CA database, I do see the expected line:
If I empty the DEBUG table and then run the program against the fr-CA database, the DEBUG table remains empty. This fact leads me to believe that the stored procedure is not being executed.
Database details
Here is the definition of the stored procedure with the debug line:
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[Atms_Get_Tray_Infos]
#TrayNo AS NVARCHAR(10)
AS
BEGIN
-- DEBUG
INSERT INTO dbo.DEBUG VALUES (1, 'Top of Atms_Get_Tray_Infos');
-- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN TRY
SELECT HTRAY.SEQ_HIST_PLATEAU AS TRAYNO,
HTRAY.DATE_EXPIRATION_DATE AS EXPIRY,
HTRAY.DATE_UTILISATION_DATE AS DATEUSED,
HTRAY.LADATE_LAVAGE AS WASHDATE,
HSTE.SEQ_CODE_QUAL_STERIL AS QLTYCODE,
HSTE.NO_CHARGE AS CHGNO,
HSTE.TEST_BIO_BON AS BIOTEST,
FRML.CODE AS FORMULACODE,
TRAY.NO_TYPE_PLATEAU AS TRAYCODE,
TRAY.DESCRIPTION_S,
TRAY.EstUrgent AS URGENT
FROM dbo.HIST_PLAT HTRAY
LEFT JOIN dbo.HIST_CHARG_STE HSTE ON HTRAY.LAST_SEQ_HIST_CHARGE_STERIL = HSTE.SEQ_HIST_CHARGE_STERIL
INNER JOIN dbo.PLATEAUX TRAY ON TRAY.SEQ_PLATEAU = HTRAY.NO_SEQ_PLATEAU
INNER JOIN dbo.FORMULE FRML ON HSTE.SEQ_FORMULE = FRML.SEQ_FORMULE
WHERE HTRAY.SEQ_HIST_PLATEAU = #TrayNo
END TRY
BEGIN CATCH
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
SELECT #ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState);
END CATCH
END
I appreciate any bit of assistance that will lead me to a resolution of this issue. Thanks!
Paolo's comment, above, caused me to investigate the actual C# code that calls the stored procedure.
The code is convoluted for the sake of being convoluted, in my opinion.
There is a method is some class that handles all calls to stored procedures. I replaced that code with this basic code:
DataSet dataSet = new DataSet("ReturnDs");
using (var connection = new System.Data.SqlClient.SqlConnection(theConnectStg))
{
using (var command = new System.Data.SqlClient.SqlCommand(theStoreProcName, connection))
{
using (var dataAdapter = new System.Data.SqlClient.SqlDataAdapter(command))
{
command.CommandType = CommandType.StoredProcedure;
if (theParameterList != null)
{
foreach (String str1 in theParameterList.ToArray())
{
String parameterName = str1.Substring(0, str1.IndexOf(":"));
String str2 = str1.Substring(str1.IndexOf(":") + 1);
dataAdapter.SelectCommand.Parameters.Add(new SqlParameter(parameterName, SqlDbType.VarChar, 128));
dataAdapter.SelectCommand.Parameters[parameterName].Value = (object)str2;
}
}
dataAdapter.Fill(dataSet);
}
}
}
return dataSet;
To satisfy your curiosity, the theParameterList parameter is an array of parameters, each in the form "#variable:value". I'm not a fan, but I am stuck with the existing code for now.
So, why did the previous code fail for certain databases? I still do not know. I am curious, but I do not wish to spend any more time on this issue. My brain is tired.
Thanks for the clue, Paolo!

How to read in c# oracle XmlType from store procedure

I'm trying to create a XML in stored procedure in this way:
PROCEDURE DeviceSearched(
xml_out OUT XMLTYPE
)
IS
BEGIN
SELECT
XMLELEMENT("Values",
XMLFOREST(de_brand)
)
INTO xml_out
FROM
tbldevice de
;
END DeviceSearched;
And I trying to read xml_out in c# in this way:
...
OracleCommand command = new OracleCommand(name, conn);
command.CommandType = CommandType.StoredProcedure;
command.BindByName = true;
...
command.Parameters.Add(new OracleParameter("xml_out", OracleDbType.XmlType, ParameterDirection.Output));
With this approach the issues are two:
Oracle exception: "ORA-01422: exact fetch returns more than requested number of rows"
If I modify the query to obtain one row, the procedure is ok (I think), but in c# I don't have any result.
What am I doing wrong?
Thanks in advance
Running SELECT XMLELEMENT("Values",XMLFOREST(de_brand)) FROM tbldevice de
In plsql will NOT result a single value, So trying to fetch the result in to single variable (INTO xml_out) will result run time error ORA-01422
Using a store procedure to select data in Oracle is not apperciated, its a SQL Server approch, why not using a simple select
Examples here and here will show how ODP.Net works with XML
You may need to mix using ref corsur and XMLType to solve the matter

PL/SQL issues returning a sequence scalar value

I'm trying to return sequence.nextval to my program from a proc stored in a package. I'm pretty green when it comes to PL/SQL and I'm kind of at a loss as to what is happening. The error that is actually being return is
PLS-00306: Wrong number or types of arguments in call to PROCGET_BOOKMARKID line 1, column 7 statement ignored.
Here is my package creation code...
create or replace
package BOOKMARKS AUTHID DEFINER is
type t_Bookmark is ref cursor;
procedure procGet_Bookmarked_Information(bookmarkId in NUMBER, bookmark out t_Bookmark);
procedure procInsert_Bookmark(bookmarkId in NUMBER, currExtent in VARCHAR2, selectedLayers in VARCHAR2);
procedure procGet_Bookmark_Id(bookmarkId out NUMBER);
end BOOKMARKS;
And the proc for get_bookmark_id looks like this (the other procs work fine so I'm not going to post them)...
procedure procGet_Bookmark_Id(bookmarkId out NUMBER)
IS
BEGIN
SELECT seq_bookmarks.nextval INTO bookmarkId
FROM dual;
END procGet_Bookmark_Id;
Now, I'm sure it's not my sequence. I can get the nextval if I just query the db directly from my code by doing this...
string sql = string.Format(#"select {0}.seq_bookmarks.nextval from dual", ApplicationSchema);
Where application schema is just the db I'm connecting to in this case.
So, it appears to me that the problem is completely in my PL/SQL and that would make sense because I've hardly used it. Any ideas?
EDIT
Ok, so here is the code that is actually making the call.
DataOperationResult result = DataAccess.GetBookmarkId();
DataRow currResult = result.DataTableResult.Rows[0];
Where DataAccess is a class of just queries and the following is the code there for this specific query.
string sql = string.Format("{0}.bookmarks.procGet_Bookmark_Id", ApplicationSchema);
DataOperation operation = new DataOperation(DataOperationType.ExecuteScalar, ConnectionString, System.Data.CommandType.StoredProcedure, sql);
return operation.PerformOperation();
Application Schema is just the database we want to query. ExecuteScalar is kind of long-winded and it's code I've not written that should be assumed to work (keyword being assumed). Hopefully this is enough to get an idea of what's happening though.
I've just compiled your package, in PL/SQL Developer it works fine.
The problem seems to be with the datatypes in your C# code.
From what I see in description, you don't bind any parameters. You should bind parameters somewhere in your code, like
OracleParameter bid = new OracleParameter("bookmarkID", OracleDbType.Number);
bid.Direction = ParameterDirection.Output;
command.Parameters.Add(bid);
If there are lots of abstractions you need to deal with, you may redefine you procedure as a function:
FUNCTION procGet_Bookmark_Id RETURN INTEGER
IS
res INTEGER;
BEGIN
SELECT seq_bookmarks.nextval
INTO res
FROM dual;
RETURN res;
END procGet_Bookmark_Id;
and call it in a SELECT query:
SELECT bookmarks.procGet_Bookmark_id FROM dual;
, which you seem to be able to do.
The error: "Wrong number or types of arguments in call to blah" refers to errors in the calling code, not the called code.
You should check the following:
The parameter you're passing is a NUMBER or a type that can be easily converted from a NUMBER.
The parameter you're passing is a variable, as opposed to a literal or constant.
I believe you need to pass in the parameter in your .net code. The name you give the parameter needs to be identical in the .net code and the procedure definition.
-OR-
Use a PL/SQL function instead of a procedure. You won't need to use a parameter at all.
Edit: Assuming you are using the Microsoft Provider you will need a return parameter. Here is the .net code.
// proc is the procedure name, oraConn is the oracle connection
OracleCommand cmd = new OracleCommand(proc, oraConn);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
OracleParameter ret = new OracleParameter();
ret.Direction = System.Data.ParameterDirection.ReturnValue;
ret.OracleType = OracleType.Number;
cmd.Parameters.Add(ret);

Categories

Resources