From the "Things that go bump in the database engine" department:
This function returns what looks like a valid value, but the record is not posted (no err msg):
private String GetInterpreterTicketIDSequenceVal()
{
con = new OracleConnection(oradb);
con.Open();
String query = "SELECT TO_CHAR(SYSDATE,'YYYYMMDD-') || LTRIM(TO_CHAR(ABC.SOMETABLEID.NEXTVAL, '000000')) FROM DUAL";
cmd = new OracleCommand(query, con);
cmd.CommandType = CommandType.Text;
//MessageBox.Show(cmd.ExecuteScalar().ToString());
return cmd.ExecuteScalar().ToString();
}
...SEEMS to work (returns a value, and the insertion is (seemingly) made without squawking)... yet, no record is inserted into the database.
This kludgy (sp?) function, OTOH:
private String GetSomeTableIDSequenceVal_Fake()
{
int iYear = DateTime.Now.Year;
int iMonth = DateTime.Now.Month;
int iDay = DateTime.Now.Day;
int iHour = DateTime.Now.Hour;
int iSecond = DateTime.Now.Second;
String sYear = iYear.ToString();
String sMonth = iMonth.ToString();
String sDay = iDay.ToString();
String sHour = iHour.ToString();
String sSecond = iSecond.ToString();
if (iMonth < 10)
{
sMonth = String.Format("0{0}", sMonth);
}
if (iDay < 10)
{
sDay = String.Format("0{0}", sDay);
}
if (iHour < 10)
{
sHour = String.Format("0{0}", sHour);
}
if (iSecond < 10)
{
sSecond = String.Format("0{0}", sSecond);
}
return String.Format("{0}{1}{2}-{3}{4}", sYear, sMonth, sDay, sHour, sSecond);
}
...works fine - the record is inserted into the database (the code that calls these functions follows).
It seems odd that they both return a string, yet one works, and one doesn't... that column doesn't have a constraint on it that is rejecting the value from the former function, so…???
Anyway, here’s the code that calls either of those functions, in context:
try
{
con = new OracleConnection(oradb);
con.Open();
String query = "INSERT INTO ABC.SOMETABLE (TICKETID, TICKETSOURCE, ABOUTSOMEID, CATEGORYID, CONTACTEMAIL) VALUES (:p_TICKETID, :p_TICKETSOURCE, :p_ABOUTSOMEID, :p_CATEGORYID, :p_CONTACTEMAIL)";
cmd = new OracleCommand(query, con);
cmd.CommandType = CommandType.Text;
// Params = TICKETID, TICKETSOURCE, ABOUTSOMEID, CATEGORYID, CONTACTEMAIL
OracleParameter p_TICKETID = new OracleParameter();
p_TICKETID.Direction = ParameterDirection.Input;
p_TICKETID.OracleDbType = OracleDbType.NVarchar2;
p_TICKETID.Size = 20;
// This doesn't allow the record to be inserted...???
//p_TICKETID.Value = GetSomeTableIDSequenceVal();
// ...but when I "fake it" below, the record IS inserted
//p_TICKETID.Value = GetSomeTableIDSequenceVal_Fake(); cmd.Parameters.Add(p_TICKETID);
OracleParameter p_TICKETSOURCE = new OracleParameter();
p_TICKETSOURCE.Direction = ParameterDirection.Input;
p_TICKETSOURCE.OracleDbType = OracleDbType.NVarchar2;
p_TICKETSOURCE.Size = 20;
p_TICKETSOURCE.Value = textBoxTicketSource.Text;
cmd.Parameters.Add(p_TICKETSOURCE);
OracleParameter p_ABOUTSOMEID = new OracleParameter();
p_ABOUTSOMEID.Direction = ParameterDirection.Input;
p_ABOUTSOMEID.OracleDbType = OracleDbType.Int32;
p_ABOUTSOMEID.Value = textBoxAboutSOMEID.Text;
cmd.Parameters.Add(p_ABOUTSOMEID);
OracleParameter p_CATEGORYID = new OracleParameter();
p_CATEGORYID.Direction = ParameterDirection.Input;
p_CATEGORYID.OracleDbType = OracleDbType.Int32;
p_CATEGORYID.Value = textBoxCategoryID.Text;
cmd.Parameters.Add(p_CATEGORYID);
OracleParameter p_CONTACTEMAIL = new OracleParameter();
p_CONTACTEMAIL.Direction = ParameterDirection.Input;
p_CONTACTEMAIL.OracleDbType = OracleDbType.NVarchar2;
p_CONTACTEMAIL.Size = 100;
p_CONTACTEMAIL.Value = textBoxContactEmail.Text;
cmd.Parameters.Add(p_CONTACTEMAIL);
try
{
cmd.ExecuteNonQuery();
}
catch (OracleException ex)
{
MessageBox.Show(ex.Message);
}
MessageBox.Show("Apparent success");
}
finally
{
con.Close();
con.Dispose();
}
Update:
I added Xaction support, and it seems to make no difference whatsoever:
I encased it in a Transaction, and it makes no difference:
OracleTransaction ot;
. . .
try
{
ot = con.BeginTransaction();
cmd.Transaction = ot;
cmd.ExecuteNonQuery();
ot.Commit();
}
catch (Exception ex)
{
ot.Rollback();
}
Update redux:
Luke made a good point about using two simultaneous connections; so, I changed that code to this:
private String GetInterpreterTicketIDSequenceVal()
{
String query = "SELECT TO_CHAR(SYSDATE,'YYYYMMDD-') || LTRIM(TO_CHAR(ABC.SOMETABLEID.NEXTVAL, '000000')) FROM DUAL";
OracleCommand oc = new OracleCommand(query, con);
oc.CommandType = CommandType.Text;
String s = oc.ExecuteScalar().ToString();
try
{
return s;
}
catch (OracleException ex)
{
MessageBox.Show(ex.Message);
return string.Empty;
}
}
...but still no joy in Mudville.
Update redux revisited:
I got it working; thanks everybody for your help and insight.
Actually, it had been working for awhile – my stupid query in Toad was the problem – I forgot that I was adding a slightly different value in new records than what I was querying for … so it looked like the records weren’t being added, but they really were.
tgif!
I tried running your code above and I was only able to reproduce problems with it if the INTERPRETERTICKETID sequence had gone beyond 999999. If you are having problems then there must be something that you are not telling us. For example, how is your table INTERPRETERTICKET defined? What constraints are on it? How is the sequence defined? Are there any triggers on the table?
Is there any need for your GetInterpreterTicketIDSequenceVal() method to use its own connection to the database? Can it not just use the same connection that the rest of your code does?
If your sequence INTERPRETERTICKETID has gone beyond 999999 then the TO_CHAR call will return a string of hashes:
SQL> select ltrim(to_char(999999, '000000')) from dual;
LTRIM(T
-------
999999
SQL> select ltrim(to_char(1000000, '000000')) from dual;
LTRIM(T
-------
#######
I put a PK constraint on the TICKETID column and after running your code twice, I got a constraint violation error.
EDIT:
In response to your comment, it is possible to use a trigger to populate the TICKETID column. You mentioned that your database apparently contains one such trigger, but without seeing how the trigger is defined, it's difficult to know what the problem with it could be.
I added the following trigger, and modified the C# code so that it didn't attempt to insert a value for TICKETID. I ran the C# code a few times and it seemed to work.
CREATE OR REPLACE TRIGGER INTERPRETERTICKETS_BI
BEFORE INSERT ON INTERPRETERTICKETS
FOR EACH ROW
BEGIN
SELECT TO_CHAR(SYSDATE,'YYYYMMDD-') || LTRIM(TO_CHAR(INTERPRETERTICKETID.NEXTVAL, '000000'))
INTO :new.TICKETID
FROM DUAL;
END;
/
the way you setup the parameters seems very strange since your parameter object end up without a name - try changing your code similar to this:
OracleParameter p_TICKETID = new OracleParameter("p_TICKETID", OracleDbType.NVarchar2, ParameterDirection.Input);
p_TICKETID.Size = 20;
Related
I am trying to update a column of type Number(19, 2) in my Oracle database using following code in C#. However, it does not update the data in the table. Amount - is of type Number(19,2) in database and I tried replacing Varchar2 with decimal, Int64, Long but still no luck. And request.amount is of a float type.
Any tips would be highly appreciated. Thanks
try
{
OracleCommand command2 = new OracleCommand();
command2.CommandText = "Update t_payment set amount = :amount where penalty_order_id = (select id from t_penalty_order where protokol_no = :invoiceNumber)";
command2.Parameters.Add(new OracleParameter(#"invoiceNumber", OracleDbType.Varchar2, 255)).Value = request.invoiceNumber;
command2.Parameters.Add(new OracleParameter(#"amount", OracleDbType.Varchar2, 255)).Value = request.amount; //(Convert.ToInt32 (request.amount) + paid_amount);
command2.Connection = connection;
command2.CommandType = System.Data.CommandType.Text;
command2.ExecuteNonQuery();
}
catch (Exception e)
{
completePayment.code = 111;
completePayment.message = e.Message;
completePayment.transactionNumber = null;
}
I found the problem. It was in the order of adding parameters. I had to add amount parameter value first and then protokol_no.
When i run my code in the debugger and I hover my mouse over the parameters they do have the right values in them. It just doesn't update my database but when I copy the query and put it into the database it works without a problem.
The parameter values are:
id = 7
omschrijving = douche muntjes
prijs = 0,5
catagorie = faciliteiten
I checked the connection tring by using an insert query and that does add records to my database. And There is an id with the value of 7 in the database.
When I run a insert query or a delete query through my C# code it does work it's just the update statement that doesn't work. If anyone sees the issue please help me.
public static void wijzigprijs(int id, string omschrijving, decimal prijs, string catagorie)
{
try
{
try
{
OleDbConnection verbinding = new OleDbConnection(
#"Provider=Microsoft.ACE.OLEDB.12.0;
Data Source=..\..\..\La_Rustique.accdb;
Persist Security Info=False;");
verbinding.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
OleDbCommand query = new OleDbCommand();
query.CommandText = #"UPDATE prijslijst
SET omschrijving = #omschrijving,
prijs = #prijs,
catagorie = #catagorie
WHERE id = #id";
query.Parameters.Add(new OleDbParameter("#id", OleDbType.Integer));
query.Parameters["#id"].Value = id;
query.Parameters.Add(new OleDbParameter("#omschrijving", OleDbType.VarChar));
query.Parameters["#omschrijving"].Value = omschrijving;
query.Parameters.Add(new OleDbParameter("#prijs", OleDbType.Decimal));
query.Parameters["#prijs"].Value = prijs;
query.Parameters.Add(new OleDbParameter("#catagorie", OleDbType.VarChar));
query.Parameters["#catagorie"].Value = catagorie;
query.Connection = verbinding;
query.ExecuteNonQuery();
MessageBox.Show("succesvol gewijzigd");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
verbinding.Close();
}
}
EDIT UPDATE
Look at this topic. Here he explains how you should use variables with OleDbCommand
Variables with OleDbCommand
This is how you typically will do it when using SQLCommand parameters:
I know this doesnt answer your questions quite, but when i use SQLCommand i use this code whenever i want to update or insert with variables:
string query = #"UPDATE prijslijst
SET omschrijving = #omschrijving,
prijs = #prijs,
catagorie = #catagorie
WHERE id = #id";
SqlCommand cmd = new SqlCommand(query, connDatabase);
cmd.Parameters.Add("#id", SqlDbType.integer).Value = 7;
cmd.ExecuteNonQuery();
connDatabase.Close();
So you should be able to do the samething. Hope this will help you.
I have never seen OleDB queries written in the above syntax.
To state it differently: OleDB simply does not use named parameters, it uses the position only.
Try to change your SQL statement like this:
query.CommandText = #"UPDATE prijslijst
SET omschrijving = ?,
prijs = ?,
catagorie = ?
WHERE id = ?";
and then add the parameters in sequence of above in the code
below that.
I follow below steps to update an oracle table:
First calculate observable collection; property indicating a column. Display this information in a WPF datagrid. I save this information to the Oracle database. This seems to work fine.
While the grid is open, I change the some cell values. I re-saved the modified values to the table. This also works fine.
I try to get updated/modified values to perform some other calculation. I noticed that my program still used the initially saved values; it didnt pick modified values even though database shows correct values. Does is happen because I am not committing / closing the Oracle connection properly?
Here is my code to save the data into Oracle table:
using (OracleConnection thisConnection = new OracleConnection(connectionname))
{
string query = "INSERT INTO TEST(WellBore,PDate, Pressure,Temperature)VALUES(:WellBore,:PDate,:Pressure,:Temperature)";
OracleCommand myAccessCommand = new OracleCommand(query, thisConnection);
var sdate = Datetime.Now.Date.ToShortDateString();
myAccessCommand.Parameters.Add("WellBore", OracleDbType.NVarchar2, 20).Value = “ABC”;
myAccessCommand.Parameters.Add("PDate", DateTime.Parse(sdate));
myAccessCommand.Parameters.Add("Pressure", OracleDbType.Decimal).Value = 1000;
myAccessCommand.Parameters.Add("Temperature ", OracleDbType.Decimal).Value = 50;
thisConnection.Open();
myAccessCommand.ExecuteNonQuery();
thisConnection.Dispose();
}
So I believe my question how do I commit the connection?
Here's an example using an insert statement with a transaction. It also grabs a returned id value, which may not be needed in your case, but anyway:
int event_id = 0;
using (OracleConnection oraConn = new OracleConnection(connStr))
{
string cmdText = #"insert into EVENT
(EVENT_NAME, EVENT_DESC)
values
(:EVENT_NAME, :EVENT_DESC)
RETURNING EVENT_ID INTO :EVENT_ID
";
using (OracleCommand cmd = new OracleCommand(cmdText, oraConn))
{
oraConn.Open();
OracleTransaction trans = oraConn.BeginTransaction();
try
{
OracleParameter prm = new OracleParameter();
cmd.BindByName = true;
prm = new OracleParameter("EVENT_NAME", OracleDbType.Varchar2); prm.Value = "SOME NAME"; cmd.Parameters.Add(prm);
prm = new OracleParameter("EVENT_DESC", OracleDbType.Varchar2); prm.Value = "SOME DESC"; cmd.Parameters.Add(prm);
prm = new OracleParameter("EVENT_ID", OracleDbType.Int32, ParameterDirection.ReturnValue); cmd.Parameters.Add(prm);
cmd.ExecuteNonQuery();
trans.Commit();
// return value
event_id = ConvertFromDB<int>(cmd.Parameters["EVENT_ID"].Value);
}
catch
{
trans.Rollback();
throw;
}
finally
{
trans.Dispose();
}
oraConn.Close();
}
}
Note: The "ConvertFromDB" is just a generic to cast the return value to its .NET equivalent (an int in this case). Again, if you aren't capturing a returned value, you don't need to worry about it.
I want to shift some variables by one. I searched for the command for it but I couldn't find. If anybody knows it please help me.
Here is the code:
private int shiftNumbers(int number)
{
int newNumber = 0;
string stm = "UPDATE devices SET number= #newNumber WHERE number>#number";
try
{
con.Open();
cmd = new MySqlCommand(stm, con);
cmd.Parameters.AddWithValue("#number", number);
}
catch (Exception e)
{
ErrorMessage = e.Message;
con.Close();
return null;
}
try
{
rdr = cmd.ExecuteReader();
while(rdr.Read()) {
newNumber = rdr.GetInt32(1);
cmd.Parameters.AddWithValue("#newNumber ", (newNumber-1));
}
}
catch (Exception e)
{
ErrorMessage = e.Message;
con.Close();
return null;
}
con.Close();
return 1;
}
I know this code useless but I show it for you to get the logic that I want to do.
I think your approach is wrong.
First, you read from the database, using a select statement;
Then you go over that result, your rdr.Read();
Then you create a new command, updating the original record;
Move forward in your reader (rdr) and repeat from 2 until you are done.
What you are doing now is impossible. You can't get a result set from an update, just a count affected.
Or, if you can, let your update statement do the calculation (it seems it is only subtracting one from the original number, so why not do that in SQL?):
string stm = "UPDATE devices SET number = number - 1 WHERE number>#number";
Yes, your code is really useless. In your update statement you are passing a parameter #newNumber bu not providing it. Closing the connection in catch block.
string stm = "UPDATE devices SET number= #newNumber WHERE number>#number";
First decide from where you are going to get the #newNumber value and then add that as parameter and use ExecuteNonQuery() method.
If you want pass the other parameter as well in your method and use it like
private int shiftNumbers(int number, int newNumber)
{
//int newNumber = 0;
string stm = "UPDATE devices SET number= #newNumber WHERE number>#number";
using(SqlConnection con = new SqlConnection(connectionString))
{
cmd = new MySqlCommand(stm, con);
SqlParameter paramNumber = new SqlParameter("#number", SqlDbType.Int);
paramNumber.Value = number;
SqlParameter paramNewNumber = new SqlParameter("#newNumber", SqlDbType.Int);
paramNewNumber.Value = newNumber;
cmd.Parameters.Add(paramNumber);
cmd.Parameters.Add(paramNewNumber);
con.Open();
cmd.ExecuteNonQuery();
}
//Rest of your code logic if any
}
For the past few hours I am trying to do the simplest of the simple things (at least for SQL SERVER) in an Oracle Data Base, through a .NET application using ADO.NET. It seems impossible.
For SQL SERVER I would do this simple task, supposing I have an SqlCommand object
comm.CommandText = #"
DECLARE #next_id INT
SET #next_id = (SELECT ISNULL(MAX(id_col),0) FROM TABLE_1) + 1
INSERT INTO TABLE_1 (id_col, col1, ...) VALUES (#next_id, val1, ...)
SELECT #next_id";
int id = Convert.ToInt32(comm.ExecuteScalar());
That would insert a new record to table TABLE_1 and I would take back the new id in the "id" variable in c# code.
Four simple steps
Declare a variable
Set it to the next available id
Insert the record with the new variable
Return the variable's value
Ok I managed to declare the variable in Oracle query. Also I (think) I managed to give it a value (With SELECT INTO)
How can I get back this variable's value back in c#? How can i SELECT a variable's value to the output stream in Oracle SQL?
I know that there are better ways to achieve getting back an identity column, but that's not the question here. It could be a totally different example. The question is simple.: I have declared a variable inside an oracle sql script that will be executed from within .net app. How can i get the variable's value back to c#, from an oracle query? What is the above code's equivalent with Oracle ADO.NET query?
You'll want to use ODP.NET (Oracle's Oracle Data Access Components):
An example of this is below. Note that in ODP.NET, you can establish a parameters direction (input, inputoutput, output, returnvalue) to correspond with the parameters of the procedure or statement you're running. In this example, I'm grabbing a returnvalue, which is an ID that is generated by the db via a sequence and trigger (its created automagically as far as the .NET app is concerned):
int event_id = 0;
using (OracleConnection oraConn = new OracleConnection(connStr))
{
string cmdText = #"insert into EVENT
(EVENT_NAME, EVENT_DESC)
values
(:EVENT_NAME, :EVENT_DESC)
RETURNING EVENT_ID INTO :EVENT_ID
";
using (OracleCommand cmd = new OracleCommand(cmdText, oraConn))
{
oraConn.Open();
OracleTransaction trans = oraConn.BeginTransaction();
try
{
OracleParameter prm = new OracleParameter();
cmd.BindByName = true;
prm = new OracleParameter("EVENT_NAME", OracleDbType.Varchar2);
prm.Value = "SOME NAME"; cmd.Parameters.Add(prm);
prm = new OracleParameter("EVENT_DESC", OracleDbType.Varchar2);
prm.Value = "SOME DESC"; cmd.Parameters.Add(prm);
prm = new OracleParameter( "EVENT_ID"
, OracleDbType.Int32
, ParameterDirection.ReturnValue);
cmd.Parameters.Add(prm);
cmd.ExecuteNonQuery();
trans.Commit();
// return value
event_id = ConvertFromDB<int>(cmd.Parameters["EVENT_ID"].Value);
}
catch
{
trans.Rollback();
throw;
}
finally
{
trans.Dispose();
}
oraConn.Close();
}
}
The ConvertFromDB is just a generic to cast the return value to its .NET equivalent (an int in this case).
Hope that helps.
EDIT:
You can easily bind an array of values (and retrieve an array of return values) in ODP.NET:
using (OracleConnection oraConn = new OracleConnection(connStr))
{
string cmdText = #"insert into TEST_EVENT
(EVENT_NAME, EVENT_DESC)
values
(:EVENT_NAME, :EVENT_DESC)
RETURNING EVENT_ID INTO :EVENT_ID
";
using (OracleCommand cmd = new OracleCommand(cmdText, oraConn))
{
oraConn.Open();
OracleTransaction trans = oraConn.BeginTransaction();
try
{
string[] event_names = new string[2];
string[] event_descs = new string[2];
int[] event_ids = new int[2];
event_names[0] = "Event1";
event_descs[0] = "Desc1";
event_names[1] = "Event2";
event_descs[1] = "Desc2";
OracleParameter prm = new OracleParameter();
cmd.Parameters.Clear();
cmd.ArrayBindCount = 2;
cmd.BindByName = true;
prm = new OracleParameter("EVENT_NAME", OracleDbType.Varchar2);
prm.Value = event_names; cmd.Parameters.Add(prm);
prm = new OracleParameter("EVENT_DESC", OracleDbType.Varchar2);
prm.Value = event_descs; cmd.Parameters.Add(prm);
prm = new OracleParameter( "EVENT_ID"
, OracleDbType.Int32
, ParameterDirection.ReturnValue);
cmd.Parameters.Add(prm);
cmd.ExecuteNonQuery();
trans.Commit();
// get return values
event_ids = (int[])(cmd.Parameters["EVENT_ID"].Value);
}
catch
{
trans.Rollback();
throw;
}
finally
{
trans.Dispose();
}
oraConn.Close();
}
}