2

In c#, after executing Oracle insert statement, I want to return sequence value that has been assigned to inserted record in the table, which has sequence-based id increment trigger on it. And then I want to set textbox value to that new Id.

I've tried that way after searching about, but the idea it not very clear to me:

  • can id be returned into textbox directly?

  • Is the word id after the returning keyword, a column name?

  • what should I do next?

    INSERT INTO teams (name) VALUES ('West Ham United') RETURNING id INTO :textbox

I have also tired this

cmd.Parameters.Add(new OracleParameter(parameterName = ":OUT_CUST_ID", OracleDbType.Int64, direction = ParameterDirection.Output));
T.S.
  • 18,195
  • 11
  • 58
  • 78
samer
  • 193
  • 5
  • 21
  • Create a `PROCEDURE` which wraps the `INSERT` statement and has an out parameter into which you can return the sequence value. – MT0 Mar 19 '16 at 01:01

4 Answers4

1

You seem doing right things. Use RETURNING INTO and ExecuteNonQuery with output parameter. Considering that you're using ODP.NET:

string sql = @"INSERT INTO teams (name) 
               VALUES ('West Ham United') 
               RETURNING id INTO :1";

using (var cmd = new OracleCommand(sql, conn))
{
    cmd.CommandType = CommandType.Text;
    cmd.Parameters.Add(":1", OracleDbType.Decimal, ParameterDirection.Output);
    // !!! If your output parameter is of String Type, 
    // it is necessary to specify "size"
    if (cmd.ExecuteNonQuery() > 0)
    {
        txtData.Text = ((OracleDecimal)cmd.Parameters[0].Value).ToInt32().ToString();
    }
}

Oracle output numeric parameter value is actually Oracle type, which you need to convert.

T.S.
  • 18,195
  • 11
  • 58
  • 78
  • yes you are right i am using ODP.NET the out put paramerter is number datatype.... after testing your suggestion i got an error said "Specified cast is not valid." a tline txtData.Text = ((OracleDecimal)cmd.Parameters[0].Value).ToInt32().ToString(); – samer Mar 19 '16 at 08:32
  • i think that caused by incorrect conversion so if the database column type is number to which datatype i have to convert to if its not int64 ??! and what the OracleDecimal meaning ? what is used for ? – samer Mar 19 '16 at 08:37
  • i have changed what you suggest to this txtData.Text = (cmd.Parameters[0].Value).ToString();.. now its working but returning wrong column value its not returning the id column value which filed by sequence trigger it returning the value of next column – samer Mar 19 '16 at 08:48
  • problem solved I will post the full answer according to your suggestion :) thanks – samer Mar 19 '16 at 08:51
  • @samer Unfortunately I don't know full scope of your code. Why, for example `cmd.Parameters[0]` returning different column? In the code above there is only 1 parameter. So, calling `cmd.Parameters[0]` or `cmd.Parameters[":1"]` should bring the same result. If you have other parameters, than that is the reason. `OracleDecimal` is ODP.NET type that used in cases such this. You need to understand that Ora DB types don't match .NET types. If the column is `NUMBER`, it doesn't mean it will match to .net `Int32`. `number(9) < Int32` and `number(10) > Int32` – T.S. Mar 19 '16 at 12:58
  • I actually know why I use `decimal` everywhere - because some of our `number` columns are `number(10)` and others are `number(38)`. Try to get my code again and replace `OracleDbType.Int32` with `OracleDbType.Decimal` and see if it works. I guess, in your case it needed no conversion because in DB your number is not too large, so you got away with `cmd.Parameters[":1"].Value`. But calling `ToString()` on it directly could be dangerous because in some cases `Value` can be `null`. May be not in your case thought – T.S. Mar 19 '16 at 13:03
  • @samer And lastly, optimizing your code is up to you. I only gave you THE idea how it is done in general. One of your questions was, `can return the id into the textbox directly?` - I answered how to do it to my best ability without knowing your DB structure, your trigger, etc. But I can go on about it. For example, instead of `'West Ham United'` you can or even should do `... (:1) RETURNING into INTO :2` and have 2 parameters there. Also, remember, parameters come in order but ODP has a property in command that allow you go by parameter name instead of order. There a lot of optimizing to do – T.S. Mar 19 '16 at 13:11
  • yes I have mass in my mind about about oracle datatype and .net datatype i don't really understand them very well, but I got your viewpoint clearly... and yes i had many parameters within my code and what i post is just an example to my idea so when i get the way ill do it on my own so i am not just copy and paste machine.. and expect that reason why i am getting worn value, but also i don't understand why you use the [0] or [1] or whatever it is why you just pass the out parameter name ? I tried to get ur code back with ur suggestion and i got same error... – samer Mar 19 '16 at 13:25
  • your totally right about null value i was not expecting that but maybe we can control this my if null then messagebox in... I planed to check all textboxs before calling the insert statement – samer Mar 19 '16 at 13:26
  • I totally i agree with you and respecting your help a lot without knowing the whole structure and etc.. and I am still learning but you have a lot of experience i want to learn from.. the best way and best method.. i have to ask general question then since i don't actually know what the best – samer Mar 19 '16 at 13:32
  • that cmd.Parameters.Add(":OUT_CUST_ID", OracleDbType.Decimal, ParameterDirection.Output); works with that TB_CUST_ID.Text = (cmd.Parameters[":OUT_CUST_ID"].Value).ToString(); – samer Mar 19 '16 at 13:33
  • ur using the OracleDbType.Decimal to restrict the case of inconsistency between db and .net datatype – samer Mar 19 '16 at 13:34
  • Well-yes. Not to "restrict" -to **abstract** ORADB and .NET data types. :-) `:1` - interesting question - This is just a name. `:OUT_CUST_ID` - long name. `:1` - short name :-). To tell you the truth, I don't write code like this anymore. I wrote query generator - `(new tbl()).Name="t"; tbl.addField("f1"); tbl.AddJoin(...); tbl.AddWhere("f2",5, EqualityType.Equals)`. Then, when data provider calls `tbl.ToSql()`, I get `WHERE f2 = :1`. It also abstracts Sql Server & ORA and based on it generates `:1` or `@1`. Soon we might support MySql & SAP Hana. `:1` is generated-I used to it – T.S. Mar 19 '16 at 14:10
  • hahah OKAY the way you are talking about seems interesting but I felt that ill throw my code away and rebuild it with the way you talked about.. any link for that way whats called etc ?? – samer Mar 19 '16 at 14:31
  • SQL Generation is not a new concept. There are probably as many home-grown varieties as many companies. For strictly CRUD type of queries Entity Framework is good. There is also Linq-to-Sql. There are commercial ORM products. There is Enterprise Library Data Blocks. I like home-grown because it allows for better crosscutting. But many people have no time to do it – T.S. Mar 19 '16 at 15:26
0

Use a procedure (and as an added bonus you won't need the trigger as you can encapsulate the trigger's logic into the procedure as well):

CREATE OR REPLACE PROCEDURE add_team(
  i_name IN  TEAMS.NAME%TYPE,
  o_id   OUT TEAMS.ID%TYPE
)
AS
BEGIN
  INSERT INTO teams (
    id,
    name
  ) VALUES (
    TEAMS_SEQ.NEXTVAL,
    i_name
  )
  RETURNING id INTO o_id;
END;
/

Then just call the procedure from your code.

Community
  • 1
  • 1
MT0
  • 143,790
  • 11
  • 59
  • 117
0

according to @T.S. suggestion I made some changes

removing (OracleDecimal) removing .ToInt32() replacing cmd.Parameters[0].Value with cmd.Parameters[0].Value

which containing the the parameter name :1

that let the code works below the working code

    string sql = @"INSERT INTO teams (name) 
               VALUES ('West Ham United') 
               RETURNING id INTO :1";

using (var cmd = new OracleCommand(sql, conn))
{
    cmd.CommandType = CommandType.Text;
    cmd.Parameters.Add(":1", OracleDbType.Int32, ParameterDirection.Output);
    // !!! If your output parameter is of String Type, 
    // it is necessary to specify "size"
    if (cmd.ExecuteNonQuery() > 0)
    {
        txtData.Text = (cmd.Parameters[":1"].Value).ToString();
    }
}
samer
  • 193
  • 5
  • 21
0

Thank you all fro your help below an example for returning sequence value from trigger after executing Oracle insert statement...

 public void data_insert()
    {
        string connstr = "User Id=user;Password=pwd;";
        string cmdtxt = @"insert into customers 
                          (CUST_ID,F_NAME,CUST_PHONE1,CUST_PHONE2,EMAIL)
                          values (null,:TB_NAME,:TB_PHONE1,:TB_PHONE2,:TB_EMAIL)
                          RETURNING CUST_ID into :OUT_ID";

        using (OracleConnection conn = new OracleConnection(connstr))
        using (OracleCommand cmd =new OracleCommand(cmdtxt,conn))
        {
            cmd.Parameters.Add(new OracleParameter("TB_NAME", TB_NAME.Text));
            cmd.Parameters.Add(new OracleParameter("TB_PHONE1", TB_PHONE1.Text));
            cmd.Parameters.Add(new OracleParameter("TB_PHONE2", TB_PHONE2.Text));
            cmd.Parameters.Add(new OracleParameter("TB_EMAIL", TB_EMAIL.Text));

            cmd.Parameters.Add(":OUT_ID", OracleDbType.Decimal, ParameterDirection.Output);

            cmd.CommandText = cmdtxt;
            conn.Open();
            cmd.ExecuteNonQuery();

            TB_CUST_ID.Text = (cmd.Parameters[":OUT_ID"].Value).ToString();
        }
    }
samer
  • 193
  • 5
  • 21