Parameterized query in Oracle trouble - asp.net

I'm using Oracle.DataAccess rather than the obsolete System.Data.OracleClient and I seem to be having trouble passing multiple parameters to my update query
This works
OracleCommand.CommandText = "UPDATE db SET column1 = :param1 WHERE column2 = 'Y'"
OracleCommand.Parameters.Add(New OracleParameter("param1", "1234"))
But I want to be able to pass multiple parameters
Here's my full code
OracleConn.Open()
OracleCommand = OracleConn.CreateCommand()
OracleCommand.CommandText = "UPDATE db SET column1 = :param1 WHERE column2 = :param2"
OracleCommand.CommandType = CommandType.Text
OracleCommand.Parameters.Add(New OracleParameter("param1", "1234"))
OracleCommand.Parameters.Add(New OracleParameter("param2", "Y"))
OracleCommand.ExecuteNonQuery()
My SELECT query seems to work when passing multiple parameters but not the update one

Although I can't see anything wrong with your example, I wonder if you're being hit by the old BindByName problem. By default, ODP.NET binds parameters to the query in the order in which they are added to the collection, rather than based on their name as you'd like. Try setting BindByName to true on your OracleCommand object and see if that fixes the problem.
I've had this problem so many times that I use my own factory method to create commands which automatically sets this property to true for me.
Classic useless Oracle documentation here

To emulate the default behavior of the System.Data.OracleClient, you should set the OracleCommand to bind by name.
OracleCommand.BindByName = True

Try newing up your OracleParameter with a the type specified. Set the value of the object before adding it to the parameters list.
var param1 = new OracleParameter( "param1", OracleType.Int32 );
param1.Value = "1234";
OracleCommand.Parameters.Add( param1 );

Try this, hope it works. It does compile.
Not sure if you also have to send a commit...
I always do this sort of thing through a stored procedure, so I have a commit after the update statement in the stored procedure.
Harvey Sather
OracleConnection ora_conn = new OracleConnection("connection string");
OracleCommand ora_cmd = new OracleCommand("UPDATE db SET column1 = :param1 WHERE column2 = :param2", ora_conn);
ora_cmd.CommandType = CommandType.Text;
ora_cmd.BindByName = true;
ora_cmd.Parameters.Add(":param1", OracleDbType.Varchar2, "1234", ParameterDirection.Input);
ora_cmd.Parameters.Add(":param2", OracleDbType.Varchar2, "Y", ParameterDirection.Input);
ora_cmd.ExecuteNonQuery();

The first code block is correct: use a colon in front of the parameter name, but not in the first argument to OracleParameter.
If no errors are thrown, it could be that the UPDATE runs successfully, it just doesn't update any records based on the WHERE clause and its substituted parameter value. Try doing it on a test table with no WHERE clause in the UPDATE to make sure it does something.

Here's the type of structure I usually use (sorry, this is from memory) :
int rows = 0;
using ( OracleConnection conn = new OracleConnection(connectionString) ) {
using ( OracleCommand cmd = conn.CreateCommand() ) {
cmd.CommandText = "UPDATE table SET column1 = ':p1 WHERE column2 = :p2";
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue(":p1", p1Val);
cmd.Parameters.AddWithValue(":p2", p2Val);
rows = cmd.ExecuteNonQuery();
}
}
The key difference is the use of the AddWithValue - I don`t remember why I ended up using that, but do remember having problems with some of the other ways of doing it.

Related

Stored Procedure not working from ASP.NET

I have the following stored procedure:
alter proc SPCP_ProgramUpdate
#ID int,
#UserID int,
#Name nvarchar(150),
#University int,
#Level tinyint,
#isActive bit
as
update tblUniversityProgram set University_Fkey = #University, Level_Fkey = #Level, Program_Name = #Name, EditDate = GETDATE(), EditUser = #UserID, isActive = #isActive
where tblUniversityProgram.ID = #ID
When I run the stored procedure from SSMS, it works as intended.
However, when I run that stored procedure from ASP.NET using this code:
Dim varDbconn As New SqlConnection
Dim varDbcomm As SqlCommand
Dim varDbRead As SqlDataReader
varDbconn.ConnectionString = ConfigurationManager.ConnectionStrings("CPDB_ConnectionString").ToString
varDbconn.Open()
If Request.QueryString("program") <> "" Then
varDbcomm = New SqlCommand("SPCP_ProgramUpdate", varDbconn)
varDbcomm.CommandType = CommandType.StoredProcedure
varDbcomm.Parameters.AddWithValue("#ID", Request.QueryString("program")).DbType = DbType.Int32
varDbcomm.Parameters.AddWithValue("#UserID", Session("UserID")).DbType = DbType.Int32
varDbcomm.Parameters.AddWithValue("#University", Session("DecryptID")).DbType = DbType.Int32
varDbcomm.Parameters.AddWithValue("#Level", ddlLevel.SelectedValue).DbType = DbType.Byte
varDbcomm.Parameters.AddWithValue("#isActive", chkisActive.Checked).DbType = DbType.Boolean
varDbcomm.Parameters.AddWithValue("#Name", txttitle.Text).DbType = DbType.String
varDbcomm.ExecuteNonQuery()
varDbcomm.Dispose()
Else
....
End IF
varDbconn.Close()
nothing happens.
Any ideas?
The most likely answer to your question is that the value you are getting out of the querystring for program is not the Id in your database that you expect.
At the minute, your code is reading in input values and passing them to a stored procedure without any validation of your expected values - missing session for example could cause you all sorts of unexpected issues.
Debug your code and see exactly what parameters you are passing to your DB. Check your connection string to see that you are hitting the database where you have amended your stored procedure.
What you have should work. I would use parmaters.Add in place of addwith, but that should not really matter.
Try adding this code right after you are done setting up the parmaters:
Debug.Print("SQL = " & varDbcomm.CommandText)
For Each p As SqlParameter In varDbcomm.Parameters
Debug.Print(p.ParameterName & "->" & p.Value)
Next
That way in the debug window (or immediate depending on VS settings), you see a list of param values, and the parameter names. I suspect one of the session() values is messed up here.

Passing a user defined table type to SQL function in Ormlite

I've to pass a table to a SQL function (till now I've passed to stored procedures and everything was fine)
Consider the following snippet
var dataTable = new DataTable();
dataTable.Columns.Add(new DataColumn("ID", typeof(Guid)));
foreach (var o in orders)
{
var r = dataTable.NewRow();
r["ID"] = o;
dataTable.Rows.Add(r);
}
var res = db.Exec(cmd =>
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add(new SqlParameter("INPUT", dataTable));
cmd.CommandText = "SELECT * FROM FUNCTION";
return cmd.ConvertToList<MyObj>();
});
I'm not aware if parameters are considered when specifing CommandType as Text, I've tried on SQLServer and it works...
What am I doing wrong? is this a limitation of ServiceStack's OrmLite?
Thanks
When manually populating cmd as in your example you're using ADO.NET (i.e. not OrmLite), so you need to find out the correct way to call a SQL Server function from ADO.NET.
It seems you can only pass a datatable to a UDF from SQL Server 2008+ and requires that your TableType parameter is READONLY.

Insert long string into Access DB using parametrised query in classic ASP

I'm trying to update a classic ASP application and as part of the update I've tried to replace dynamic SQL using string concatenation with a parametrised query.
The problem is that the parameters won't accept a value which is longer than 210 characters.
I get the following error...
ADODB.Parameter error '800a0d5d'
Application uses a value of the wrong type for the current operation.
/admin/Save_product_subcategories.asp, line 30
My first attempt looks like this...
SQLString = "UPDATE Product_SubCategories
SET SubCategory=?, Description=?
WHERE SubCategoryID=?"
Set courseCommand = Server.CreateObject("ADODB.Command")
courseCommand.ActiveConnection = objConn
courseCommand.CommandText = SQLString
courseCommand.Parameters(0).value = cleanCategory
courseCommand.Parameters(1).Value = cleanDescription
courseCommand.Parameters(2).value = cleanSubCategoryId
I've tried manually setting the parameter type and increasing the size of the parameter...
courseCommand.Parameters(1).Type = 203
courseCommand.Parameters(1).Size = 300
courseCommand.Parameters(1).Type = adLongVarWChar
I've also tried creating a parameter with the command.CreateParameter method but that gives the same error.
param = courseCommand.CreateParameter(,,,,cleanDescription)
'or
param = courseCommand.CreateParameter(,adLongVarWChar,,,cleanDescription)
'or
param = courseCommand.CreateParameter(,adLongVarWChar,,300,cleanDescription)
courseCommand.Parameters(1) = param
I'm beginning to think that my only option is to go back to dynamic sql.
Edit:
I tried to Append the parameter instead of adding it to the collection using the array index but none of the parameters worked after that.
Provider error '80020005'
Type mismatch.
/admin/Save_product_subcategories.asp, line 31
For anyone else looking for this the answer is to use a Recordset.
SQLString = "select * from Product_SubCategories where 1=0"
Set rs= Server.CreateObject("ADODB.Recordset")
rs.open SQLString , objConn, 1,3 'open as keyset ,lock optimistic that will create empty recordset for you
' Add new record
rs.AddNew
'assign values
rs("SubCategoryID")=cleanSubCategoryId
rs("Description")=cleanDescription
rs("SubCategory")=cleanCategory
' send new record with values to database
rs.Update
'close recordset
rs.close
'destroy recordset object
se rs=nothing

Return Two Data Sets

So I'm passing a ClientID to my DB and using that to look up all their details, then I want to use those details to also get all other users closely matching the details. I have all this written but my problem is I want to return the initial user's details also. For example;
Select Details = #UserDetails
from UnregisteredUserTable
where UserId = #UserID
Select BunchOfUsersWithMatchingData
from RegisteredUserTable
where UserDetails like #UserDetails
Obviously I've removed unnecessary info. But as you can see this returns all the data of the matching users but not the initial user's details. Could I use a CTE somehow?
UPDATE
Apologies, no idea my data access mattered. I'm doing pretty much the following atm but can change it no problem.
Dim results = thisObjectContext.MatcherSP(UserID)
For Each obj In results
TableData.Rows.Add(obj.IdNumber, obj.name,
obj.emailaddress1, obj.telephone1, obj.telephone2, obj.address1_line1,
obj.address1_line2)
Next
UPDATE 2
ok so I'm just using the two selects in my SP and it runs fine in SQL Server. But when I try to add it to my dbml in Visual Studio I get a strange error:
Unable to extract stored procedure 'dbo.MySP' because its result set contains muultiple anonymous columns.
Any ideas about that?
Well, this isn't VB code, but I will keep it as simple as possible.
Use a SqlDataAdapter to fill a data set. Results from both your select statements will populate different tables in the the DataSet.
cmd.CommandText = "MatcherSP";
cmd.CommandType = CommandType.StoredProcedure;
adapter = new SqlDataAdapter(cmd);
ds = new DataSet();
adapter.Fill(ds);
You can then access the data as follows:
tableA = ds.Tables[0];
tableB = ds.Tables[1];
You can use the SqlDataReader's nextresult() method.
using(SqlCommand cmd = new SqlCommand("NameOfSP",c))
{
cmd.CommandType = CommandType.StoredProcedure;
using(SqlDataReader d = cmd.ExecuteReader())
{
while(d.Read()){
//Result data from the first select
}
d.NextResult();
while(d.Read()){
//Result data from the second select
}
}
}
http://twogeeks.mindchronicles.com.dnpserver.com/?p=28&cpage=1#comment-37818
Brilliant article, outlined very clearly exactly what I wanted to do.

MySQL / ASP.NET Stored Procedures

Hopefully this is not a ServerFault question...
I'm working forward on migrating a project from storing data in XML Serialization to a MySQL database. I'm using the example provided me from a previous question answered yesterday.
Connecting using phpMyAdmin and MySQL Workbench I've created a Stored Procedure called 'sprocOrderSelectSingleItem'. It seems to work well with MySQL for all I can tell. When I run the SHOW CREATE PROCEDURE sprocOrderSelectSingleItem it returns the following:
CREATE DEFINER=username#% PROCEDURE sprocOrderSelectSingleItem(IN orderID INTEGER)
BEGIN SELECT * FROM tblOrders WHERE ID=orderID; END
My cooperative ASP.NET code goes something like this:
public static Order GetItem(int ID)
{
Order objOrder = null;
using (OdbcConnection objConnection = new OdbcConnection(Utils.ApplicationConfiguration.ConnectionString))
{
OdbcCommand objCommand = new OdbcCommand("sprocOrderSelectSingleItem", objConnection);
objCommand.CommandType = CommandType.StoredProcedure;
objCommand.Parameters.AddWithValue("orderID", ID);
objConnection.Open();
using (OdbcDataReader objReader = objCommand.ExecuteReader())
{
if (objReader.Read())
{
objOrder = FillDataRecord(objReader);
}
objReader.Close();
}
objConnection.Close();
}
return objOrder;
}
When I view the page I get the following error message:
ERROR [42000] [MySQL][ODBC 5.1 Driver][mysqld-5.0.77]You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'sprocOrderSelectSingleItem' at line 1
Really not catching on to what could be missing or going wrong. Are there any additional tests I should/could be running to confirm things are working on the MySQL side? Am I missing a step to pass the Stored Procedure call correctly in ASP.NET? The code breaks at the line of:
using (OdbcDataReader objReader = objCommand.ExecuteReader())
Replacing the line of
OdbcCommand objCommand = new OdbcCommand("sprocOrderSelectSingleItem", objConnection);
with this instead
OdbcCommand objCommand = new OdbcCommand("SELECT * FROM tblOrders WHERE ID=" + ID + ";", objConnection);
and everything works as expected.
Thanks for any help you guys can provide.
Your can run an execute on sprocOrderSelectSingleItem in Mysql directly with the ID parameter.
It will show that your StoredProc run correctly.
Here is a sample code in C# that call a stored proc.
OdbcCommand salesCMD = new OdbcCommand("{ CALL SalesByCategory(?) }", nwindConn);
salesCMD.CommandType = CommandType.StoredProcedure;
OdbcParameter myParm = salesCMD.Parameters.Add("#CategoryName", OdbcType.VarChar, 15);
myParm.Value = "Beverages";
OdbcDataReader myReader = salesCMD.ExecuteReader();
Look at the "Call" in the OdbcCommand and the "?" for the parameter that is later supplied with a value.
Can you try something like below:
OdbcCommand cmd = new OdbcCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "{call LoadCustCliOrders(?,?,?,?)}";
cmd.Parameters.Add("CUST_ID",OdbcType.Int);
cmd.Parameters.Add("CLIENT_ID",OdbcType.Int);
cmd.Parameters.Add("DATE_FROM",OdbcType.Date);
cmd.Parameters.Add("DATE_TO",OdbcType.Date);
...
cmd.Parameters["CUST_ID"].Value = _CustId;
cmd.Parameters["CLIENT_ID"].Value = _ClientId;
cmd.Parameters["DATE_FROM"].Value = _DateFrom;
cmd.Parameters["DATE_TO"].Value = _DateTo;
cmd.ExecuteReader
Are you sure that you are using the same username or user with the same access privileges.
I think you need to add the word "CALL" before the stored proc.
It should be CALL sprocOrderSelectSingleItem and try.

Resources