C# app passing weird SQL param values - c#

I'm working on an app written in C# (VS2013). It's calling a stored procedure in SQL Server. It's passing a bunch of input parameters, plus four output parameters.
My problem is that one of these output parameters is getting passed with a value that I'm not setting.
This is what SQL Server Profiler records as the procedure call. I've replaced the actual parameter names with generic names just for asking this question.
declare #p51 int
set #p51 = 300000
declare #p52 int
set #p52 = NULL
declare #p53 int
set #p53 = 7776
declare #p54 int
set #p54 = NULL
exec [dbo].[proc_name] (input param list is here)
#outparam1 = #p51 output, #outparam2 = #p52 output,
#outparam3 = #p53 output, #outparam4 = #p54 output
#outparam3/#p53 is the issue. It shouldn't have a value. It's being created with a null value like this (even though as an output parameter that shouldn't be necessary):
var spParam3 = new SqlParameter("#outparam3", SqlDbType.Int);
spParam3.Value = DBNull.Value;
There's nothing between that line of code, and the stored procedure execution, that's setting a different value for the parameter. I've set a breakpoint on the ExecuteNonQuery() call, checked the parameter list, and that parameter was still null.
I'm completely lost on why its value is getting set to 7776. Yes, that number is a code used throughout the app, but I can't tell how or why this parameter is getting set to that value.
Any thoughts on where this is happening would be greatly appreciated.

#outparam3=#p53
#p53 = 7776
thats why the value you get/insert in table is 7776

Related

C# LINQ ObjectParameter turns STP output to SQL Data type

I've been looking for answer and couldn't find it, something really weird is going on.
i have SQL Stored procedure that returns output parameter as a smallint.
ALTER PROCEDURE [STP_NAME]
#Out_Error_Level Smallint OUTPUT
SELECT #Out_Error_Level = 0
pretty simple and works perfectly when i execute thru SQL Management studio.
now what weird is that when i execute thru C# Link i get 'Bigint'. C# code is also simple:
DS_RAS_CD_APPEntities2 db = new DS_RAS_CD_APPEntities2();
ObjectParameter outputError = new ObjectParameter("Out_Error_Level", SqlDbType.SmallInt);
var updateProcessesList2 = db.STP_NAME(outputError);
Console.WriteLine(outputError.Value);
the result is : BigInt.
now when i change output in sql to different number i get some sort of data types, for example: 1 returns Binary, 2 returns Bit, 3 returns Char, 10 returns Nchar.
it ends when i set #Out_Error_Level = 35, then the result is 35.
Any help?
If you look at the constructor for ObjectParameter you will see there are two overloads:
ObjectParameter(String name, Object value)
ObjectParameter(String name, Type type)
If you look at what you are providing as the second parameter then it is not a Type so it must be using the first overload.
If we then look at what it says about that second overload:
value
Type: System.Object
The initial value (and inherently, the type) of the parameter.
So as you can see it is taking the value you have passed (SqlDbType.SmallInt) as a default value and is using this to work out the type that the object should be - in this case of course the enum SqlDbType. So every number you are passing back is being translated into its enum equivalent. Once you provide numbers that don't exist in the enum it just returns the number itself.
What you likely want to be doing is
new ObjectParameter("Out_Error_Level", typeof(Int16));
I use Int16 because that is the equivalent for the database SmallInt. You could equally use the more common Int32 and I'd expect it to work fine.
Source of information: https://msdn.microsoft.com/en-us/library/system.data.entity.core.objects.objectparameter.objectparameter(v=vs.113).aspx
To conclude if you are getting wrong results then I would advise always looking at the documentation you are provided for the objects and methods you are using and make sure that you aren't making any wrong assumptions about how it works...

Dapper Multi-mapping APIs splitOn param Error - I'm not using MultiMapping

I have a project where I interact with many stored procs. There is no bare SQL Selects.
I am using Dapper. We are not trying to use any of the MultiMapping features. I am trying to figure out why this one proc would return that error? What should I check? What should I look for?
Error:
When using the multi-mapping APIs ensure you set the splitOn param if you have keys other than Id\r\nParameter name: splitOn
You should use Execute() instead of Query(), as your SP does not return any record. Dapper assumes you are trying to get data, so maps the missing results to your model class.
I ran into this problem today, and couldn't understand why I was getting the MultiMapping error message when I wasn't actually trying to multi-map in the first place. My code uses dapper's Query instead of Execute, because the sproc does actually return some rows.
Turns out that in my stored procedure, which takes a single varchar param, if the param is passed as NULL, then the result is just return value integer 0. If its passed as an empty string, I get an empty result set on top of the normal return value 0.
Because I had told Dapper to use Query<MyClass>, it looked at the plain 0 return from the null version as an int, not a MyClass, and tried to Multimap, which is where that multimap error comes from.
To fix this, I changed my stored procedure to convert a null param into an empty string param, thus ensuring an empty result set instead of no result set, and then Dapper started happy working again.

write sql command to text file

I want to write sql command to text file with parameter values.
Following is my code for replacing parameter with appropriate values.
string commandText = commandInfo.CommandText;
if (commandInfo.Parameters.Count > 0)
{
foreach (SqlParameter parameter in commandInfo.Parameters)
{
commandText=commandText.Replace(parameter.ParameterName,parameter.Value==(object)DBNull.Value?(object)DBNull.Value:("'"+parameter.Value.ToString()+"'"));
}
}
the catch is although all other parameter values are replaced correctly.those having null values are taken up as blank i.e 'parameter1',,'param2'
between the two is the null valued parameter in final string.
What can be the alternative?
Frankly, replacing the parameters with values is (IMO) the wrong thing to do; what we do in mini-profiler is to spoof declare statements at the top of the output, so that you can copy and paste it into SSMS, without needing to worry about what is a parameter and what was hard-coded in the original TSQL. For example, glancing at the mini-profiler output for this page, I see
DECLARE #id int = 18121022,
#type tinyint = 10;
(and then lots of tsql that is very specific to us)
You can glance at the mini-profiler code to see how we output this, but basically it just involves walking over the parameters, writing a simple declare. If you are using something like ASP.NET, mini-profiler also avoids the need to write a file (instead making it available live on the site, to your developers).

Calling stored procedure with parameters

I have a stored procedure that returns a value, not a dataset, and I have problems getting it to work with EF4.
I've seen this: http://dotnet.dzone.com/news/how-retrieve-stored-procedure
Here is what I did: I added a procedure to the model, and imported a function.
The first issue that I had was the fact that parameters in my procedure are named like #_Parameter_in. That made EF to bring them in as p_Parameter_in because it wouldn't work with an underscore as the first character. Then when I called the stored procedure, I can see in the SQL Profiler call that it looks for #p_Parameter_in, and of course there was an issue with that.
Now I renamed the parameters and looked into SQL Trace - everything looks and works great. The problem is that I can't get the value out. Here is how my code looks:
System.Data.Objects.ObjectParameter newKey = new System.Data.Objects.ObjectParameter("NewKey_out", typeof(Int32));
newKey.Value = 0;
context.GetNextSurrogateKey_v2("tTest", newKey);
After calling newKey.Value, it's always 0 or whatever value I set it to. It doesn't bring the value back. I suspect my issue is with how I import the function. I use Scalars and data type Int32. "Create new Complex type" is disabled for me for some reason. Anybody had that issue?
I'm guessing here since I can't see the stored procedure that you're calling. I think you're wanting to retrieve a scalar value that has been returned by the stored procedure, rather than the value of an output parameter as defined in the stored procedure.
I believe you want to define a new Function within the EDM and point this at the stored procedure. A quick google has this potential solution: http://www.devtoolshed.com/using-stored-procedures-entity-framework-scalar-return-values
HTH
The problem is that EF process output parameters after datareader ends reading. That's usually after calling DataBind() function.
I had same problem with longer processing procedures. I solve this by using .ToList() function on ObjectResult.
var rowsCount = new ObjectParameter("RowsCount", typeof(Int32));
var result = db.GetProductList(pageSize, pageNumber, rowsCount).ToList();
this.ProductsCount = (int?)rowsCount.Value;
Single rows or values can you probably solve with FirstOrDefault() function.
I had the same issue as Jan Remunda described. Someone changed the return type from Integer to Entity.Core.Objects.ObjectResult(of Integer?) which resulted in always returning nothing.
For us the solution was to force EF to read the return of the stored proc by adding the .FirstOrDefault() function to the return.

Exception on ExecuteNonQuery method about unsuccessful value convertion

i am using OleDbCommand.ExecuteNonQuery() to insert data into the database:
ObjCommand = New OleDbCommand
ObjCommand.CommandType = CommandType.StoredProcedure
ObjCommand.CommandText = StrSQL
ObjCommand.Parameters.Add("field1", OleDbType.VarChar).Value = <something1>
ObjCommand.Parameters.Add("field", OleDbType.VarChar).Value = <something2>
(...)
(...)
ObjCommand.Parameters.Add("field50", OleDbType.VarChar).Value = <something50>
ObjCommand.Connection = GetDBConnection(StrConnectionString)
ObjCommand.Connection.Open()
<some integer> = ObjCommand.ExecuteNonQuery()
And there is a conversion exception that only shows up in the last line:
error converting datatype varchar to smallint
I'd like to know if it's the normal behavior, and how do i know where the conversion problem occurs.
update:
ObjCommand.Parameters.Add("#IdMunFatoGerador", OleDbType.VarChar).Value
= ObjNFe.idMunFatoGerador
i've found this line through commenting every line and uncommenting some, this one gives me the above said exception.
ObjNFe.idMunFatoGerador is a string and gives me "error converting datatype varchar to smallint" too
That implies that one of the parameters of the query is of the wrong type. Namely you are passing varchar when you should be passing a smallint (short in c#).
Without the definition of the stored procedure there's no way we can guess which one it is..
One of the parameters you are pasing to the stored procedure as a varChar is typed in the stored procedure as an smallint. And, in this case the value you are passing in cannot be converted implicitly by the server to an integer value. Look at the stored proc definition, Either lala, or lulu is typed as an smallint. Then look at actual values you are sending it...
If you use the DataSet designer, it will generate everything for you and you'll get a compiler error instead of a run-time error. Add a new DataSet to your project then add a Query to the DataSet.
You end up with something like this:
QueriesTableAdapter ta = new QueriesTableAdapter();
ta.Connection = myConnection;
ta.MySeveralParameterStoredProc(x0, x1, ..., xN);
I guess you could loop through the parameter collection and look at the value and see if it can be numberic (string.isnumeric). The use debug.assert to output a message that the parameter value is too big to be a small int as well as the parameter name. Even better is for you to set the parameter type to be oledbtype.smallint and then only look at those. Ultimately, you need to know your parameters and how they correspond to the underlying SQL. I would just narrow my search by typing my parameters correctly and then ensure I never passed anything to the command object that wouldn't work. HTH.
Possible code:
For each parameter as SqlParameter in mycommandobject.parameters
if isnumeric(parameter.value) then
debug.assert(convert.int32(parameter.value) <= 32,767,"This parameter could have an issue - " & parameter.parametername & " value = " & parameter.value)
end if
loop
I haven't tested the code, but i believe this will work.
I've finally found it.
It was everything ok with the formats of the values.
The problem was: one of the parameters was missing. I still didn't understand it completely, but the issue was that the missing parameter (smallint) was interpreted in the following one (varchar) and so the error i found was in the second one.
In other words, field~35 was missing (haha)
So the thing is: when mounting a command to a procedure, remember to always put the fields in the exact amount and order. =)
Thank you guys!

Categories

Resources