Stored Procedure with output parameters connected to method in C# - c#

Do you see something blatantly wrong with this line:
commaSepString1 = com.Parameters["#CommaSepString"].Value.ToString();
It shows an error like:
Object reference not set to an instance of an object.
For short, the C# method looks like:
public static DataTable GetFilmDetails(string filmId, out string
commaSepString1)
It takes the following stored procedure (that executes correctly on its own):
com.CommandText = "CatalogGetFilmDetails2";
And since #CommaSepString is an output parameter in the stored procedure, in C# I have this:
param = com.CreateParameter();
param.ParameterName = "#CommaSepString";
param.Direction = ParameterDirection.Output;
param.DbType = DbType.String;
com.Parameters.Add(param);
commaSepString1 = com.Parameters["#CommaSepString"].Value.ToString();
If you are curious about the Stored Procedure, it starts like this:
CREATE PROCEDURE CatalogGetFilmDetails2
(#FilmID int, #CommaSepString VARCHAR(50) OUTPUT) AS
The SP inserts some rows into a table variable based on some joins, it puts all values from column x from that table into a string with comma separated values:
SELECT #CommaSepString
= STUFF((SELECT ', ' + Categ FROM #Filme1 FOR XML PATH('')), 1,1,'')
then it selects the table.
Thank you for the patience to read this. Would it be more clear if I published the entire code for the stored procedure and the C# method? Not sure if I am allowed that and worried it might be too lengthy to read.
PS: There must be something wrong about the commaSepString! The code worked perfectly before I added it in both places.

SQL Server doesn't know output, it only knows input/output. So when you specify
param.Direction = ParameterDirection.Output;
SQL Server will actually read the string as well. Since you haven't supplied a value, SQL Server determines that that its length is zero.
Incredibly, if you specify the magic number -1, SQL Server will determine the size for you:
param.Size = -1;
This is perhaps the second worst gotcha about ADO.NET.
Just behind the fact that SQL NULL translates to DBNull.Value instead of null.

You should set a breakpoint on the offending line, then you should examine your parameters collection to check if the parameter exists.
If it exists, then check if its value is null.
In this case the .ToString() will give you the error described.

Related

How can a stored procedure, that is called in C#, correctly insert data without giving all optional parameters?

I'm trying to insert data with a stored procedure into my SQL Server database, from a C# program using Dapper. When I try to do this, I do not get any error, but some data is unfortunately inserted into the wrong column.
The database consists of a lot of tables and columns, hence the use of a stored procedure to insert data correctly. I have extensively tested the stored procedure in SQL Server itself and know for sure that the data is placed correctly when directly executing SQL code on the server.
Here is the code calling the stored procedure, and a tiny part of the stored procedure script.
public void AddIndividual(string genus, string species, string collection)
{
using (IDbConnection connection = new SqlConnection(connectionString: Helper.CnnVal("Rapento.Properties.Settings.Database1ConnectionString")))
{
List<Individual> individual = new List<Individual>();
individual.Add(new Individual { GivenGenusName = genus, GivenSpeciesName = species, GivenCollectionName = collection });
connection.Execute("dbo.AddIndividual #GivenGenusName, #GivenSpeciesName, #GivenCollectionName", individual);
}
}
CREATE PROCEDURE AddIndividual
#GivenGenusName varchar(255) = null,
#GivenSpeciesName varchar(255) = null,
#GivenDeterminedBy varchar(255) = null,
#GivenDeterminationDate varchar(255) = null,
....
#GivenCollectionName varchar(255) = null,
In the database, I can see that GenusName and SpeciesName are inserted correctly, but CollectionName is inserted into the column DeterminedBy. This is not how it's written in the SQL script. It comes to my attention that DeterminedBy is the third parameter in the script, which makes me think that the parameters are not passed on based on the names I give them, but based on their position (the order I in which pass them).
So my question is: How can I insert this parameter in the correct column without having to pass every single optional parameter in the procedure?
I hope I gave you all the info you need. Thanks!
When executing a stored procedure as you are above:
connection.Execute("dbo.AddIndividual #GivenGenusName, #GivenSpeciesName, #GivenCollectionName", individual);
... what you are doing is supplying a list of values, not a list of parameters. If you are skipping parameters in the stored procedure, you need to specify the names of the parameters you are filling, like this (Assumption: The parameter names are the same as your variable names):
connection.Execute("dbo.AddIndividual #GivenGenusName = #GivenGenusName, #GivenSpeciesName = #GivenSpeciesName, #GivenCollectionName = #GivenCollectionName", individual);
If you just supply values, they fill in the parameters starting with the first parameter. This is what your query is doing. The primary bit of confusion here is that the values you have set up are handled as variables, not parameters.

ORA-06550 when trying to run stored procedure in oracle c#

using (var command = new OracleCommand(sqlText, oraConnection) { CommandType = CommandType.StoredProcedure })
{
command.BindByName = true;
var parameters = command.Parameters;
parameters.Clear();
parameters.Add("p_date", OracleDbType.Date, ParameterDirection.Input).Value = DateTime.Now;
command.ExecuteNonQuery();
}
Here is my code in VS15. I am trying to execute a stored procedure and pass in my only parameter as a date.
create or replace procedure cwi_pat_deductions_export
(
:p_date date
)
is
v_count number;
This is the beginning of the stored proc. I am getting Oracle Error : ORA-06550 at line 1 col 7 (so right after the word "CREATE"). I am not a sql dev by trade, so I am struggling to see where the error is. I dont feel like it is on my end (the c# side) but it very well could be (our sql developer insists that it must be a problem on my end, as the stored proc compiles and runs fine in PlSql Developer).
are you not allowed to start stored procs with Create or replace? i thought that was standard.
You don't pass the full CREATE OR REPLACE PROCEDURE ... text of the procedure when you want to call it. The point of the procedure being stored is that this is already stored in the database.
If you want to call the stored procedure, the sqlText parameter should be just the stored procedure name, cwi_pat_deductions_export. If that doesn't work, and you get an invalid identifier error, try preceding the name with the owner of the stored procedure, for example some_schema.cwi_pat_deductions_export.

Stored procedure executes but does not update data

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.

Optional output parameter causes InvalidOperationException when no value is submitted with Enterprise lib 5.0

I'm having problem with output Parameters in Microsoft Sequel Server 2008 with Enterprise Library 5.0
I'm calling a procedure from my code (in C#) and it worked fine until I added an optional output parameter to the stored proc to track feedback.
The Code for calling the proc from my code:
string insertCommand = insertParams[0]; //the stored proc command
Object[] parameterValues = insertParams.Skip(1).ToArray(); //The parameters
int feedback = 1;
IDataReader reader = localDB.ExecuteReader(insertCommand, parameterValues); //ERROR
if (reader.Eead()){
//stuf
During debug parameterValues contains one object.
The error I get is
[System.InvalidOperationException] = {"The number of parameters does not match number of values for stored procedure."}
My stored proc looks like this:
ALTER PROCEDURE [dbo].[BS_GetDetails]
#BusStop_ID INT,
#FEEDBACK_CODE INT=NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT #FEEDBACK_CODE = 200
//Do lots of other non-related things, mostly select statements
When I call the stored proc from inside the Database with only one parameter it works fine, but as I get the error in my code after I added the extra optional output param
I could create a second stored proc to call the first, but that seems like a hacky solution and I suspect I'm missing something subtle here...
Have you looked at your parameterValues object b/f you execute call? Ive done optional parameters with only the key/value pair that I need.
cmd.Parameters.Add(
new SqlParameter("#BusStopID", myBusStopID));

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