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!
Related
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...
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
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.
This is an absolute howler. I cannot believe my own eyes, and I cannot believe nobody before me would have discovered this if it was a genuine bug in C#, so I'm putting it out for the rest of the developer community to tell me what I am doing wrong. I'm sure this question is going to involve me saying "DOH!" and smacking my head very hard with the palm of my hand - but here goes, anyway...
For the sake of testing, I have created a table Test_1, with script as follows:
CREATE TABLE TEST_1 (
COLUMN1 NUMBER(12) NOT NULL,
COLUMN2 VARCHAR2(20),
COLUMN3 NUMBER(12))
TABLESPACE USERS
STORAGE (
INITIAL 64K
MAXEXTENTS UNLIMITED
)
LOGGING;
Now I execute the following code:
var conn = new OracleConnection("connectionblahblah");
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText =
"insert into Test_1(Column1, Column2, Column3) " +
"values(:Column1, :Column2, :Column3)";
var p = cmd.Parameters;
p.Add("Column1", 1);
p.Add("Column3", null);
p.Add("Column2", "record 1");
cmd.ExecuteNonQuery();
Whoa! I get an ORA-01722 error - "invalid number"! What's wrong, though? Column1 is numeric, and has a value of 1, so that's fine; Column2 is a string, and Column3 is a nullable column, so that shouldn't cause any trouble...
Now sit down for this one... the problem here is that Column3 and Column2 are transposed in the order in which they are added to the OracleParameterCollection. Switch them around, and presto! It works!
This, of course, leads me to the next obvious experiment... let's change that block of code for adding parameters like so:
p.Add("Foo", 1);
p.Add("Bar", "record 1");
p.Add("hahahahahahaha", null);
You think that'll work? Well guess what - it does!
I am sitting here absolutely stunned. I cannot believe what I am seeing, and I likewise cannot believe that nobody before me has discovered this behavior (unless I don't know how to use Google properly).
This is not just an annoyance - it is seriously dangerous. What would have happened if I'd transposed two columns of the same data type? I wouldn't have even got an error - I would have simply inserted the wrong data into the wrong columns, and been none the wiser.
Does anyone have any ideas for a workaround - other than just being careful not to add parameters in the wrong order?
This is not a bug but explicitly mentioned in Oracle ODP.Net documentation. In a OracleCommand class the parameters are bound by position as default. If you want to bind by name then set the property cmd.BindByName = true; explicitly.
Reference to Oracle documentation.
http://download.oracle.com/docs/cd/E11882_01/win.112/e12249/OracleCommandClass.htm#i997666
Is that a typo that you have column3 being added before column2?
Because the colon syntax signifies a bind variable--name doesn't matter to BIND variables in PLSQL, they're populated in order of submission. Which would mean you'd be attempting to set column2 value as "record 1", which would explain the invalid number error...
You currently have:
p.Add("Column1", 1);
p.Add("Column3", null);
p.Add("Column2", "record 1");
...see if this alteration fixes your issue:
p.Add("Column1", 1);
p.Add("Column2", "record 1");
p.Add("Column3", null);
Getting Named Parameters to Work?
I have to defer to someone with more C# experience to explain how to get named parameters working. But I'm glad we confirmed that the colon appears to be interpreting as an Oracle BIND variable.
p.Add(":Column1", 1);
p.Add(":Column2", "record 1");
p.Add(":Column3", null);
//NOTE i have added : to the parameter names to be recognised by oracle data client
I'm working with a datagrid and adapter that correspond with an MSAccess table through a stored query (named "UpdatePaid", 3 paramaters as shown below) like so:
OleDbCommand odc = new OleDbCommand("UpdatePaid", connection);
OleDbParameter param;
odc.CommandType = CommandType.StoredProcedure;
param = odc.Parameters.Add("v_iid", OleDbType.Double);
param.SourceColumn = "I";
param.SourceVersion = DataRowVersion.Original;
param = odc.Parameters.Add("v_pd", OleDbType.Boolean);
param.SourceColumn = "Paid";
param.SourceVersion = DataRowVersion.Current;
param = odc.Parameters.Add("v_Projected", OleDbType.Currency);
param.SourceColumn = "ProjectedCost";
param.SourceVersion = DataRowVersion.Current;
odc.Prepare();
myAdapter.UpdateCommand = odc;
...
myAdapter.Update();
It works fine...but the really weird thing is that it didn't until I put in the odc.Prepare() call.My question is thus: Do I need to do that all the time when working with OleDb stored procs/queries? Why? I also have another project coming up where I'll have to do the same thing with a SqlDbCommand... do I have to do it with those, too?
This is called, oddly enough, a prepared statement, and they're actually really nice. Basically what happens is you either create or get a sql statement (insert, delete, update) and instead of passing actual values, you pass "?" as a place holder. This is all well and good, except what we want is our values to get passed in instead of the "?".
So we prepare the statement so instead of "?", we pass in parameters as you have above that are going to be the values that go in in place of the place holders.
Preparing parses the string to find where parameters can replace the question marks so all you have to do is enter the parameter data and execute the command.
Within oleDB, stored queries are prepared statements, so a prepare is required. I've not used stored queries with SqlDB, so I'd have to defer to the 2 answers previous.
I don't use it with SqlDbCommand. It seems as a bug to me that it's required. It should only be nice to have if you're going to call a procedure multiple times in a row. Maybe I'm wrong and there's a note in documentation about providers that love this call too much.
Are you using the JET OLEDB Provider? or MSDASQL + JET ODBC?
You should not need to call Prepare(), but I believe that's driver/provider dependent.
You definitely don't need to use Prepare() for System.Data.SqlClient.