views:

1721

answers:

3

With this

PROCEDURE "ADD_BOOKMARK_GROUP" (
  "NAME" IN VARCHAR2, 
  "BOOKMARK_GROUP_ID" IN NUMBER, 
  "STAFF_ID" IN VARCHAR2,
  "MAX_NO" IN INT,
  "NUMFOUND" OUT INT, 
  "NEW_ID" OUT NUMBER) IS

BEGIN

NEW_ID := -1;

SELECT COUNT(*) INTO NUMFOUND FROM BOOKMARK_GROUP_TABLE WHERE STAFF_ID = STAFF_ID;

IF NUMFOUND < MAX_NO THEN
    INSERT INTO BOOKMARK_GROUP_TABLE (NAME, BOOKMARK_GROUP_ID, STAFF_ID) VALUES(NAME, BOOKMARK_GROUP_ID, STAFF_ID);
    SELECT BGT_SEQUENCE.currval INTO NEW_ID FROM dual;
END IF;
END;

I find it interesting that if I don't add parameters in the order they were defined in, e.g.

OracleCommand cmd = new OracleCommand("ADD_BOOKMARK_GROUP", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new OracleParameter("NAME", name));
...
cmd.Parameters.Add(new OracleParameter("NEW_ID", OracleDbType.Decimal)).Direction = ParameterDirection.Output;
cmd.Parameters.Add(new OracleParameter("NUMFOUND", OracleDbType.Int32)).Direction = ParameterDirection.Output;

instead of

OracleCommand cmd = new OracleCommand("ADD_BOOKMARK_GROUP", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new OracleParameter("NAME", name));
...
cmd.Parameters.Add(new OracleParameter("NUMFOUND", OracleDbType.Int32)).Direction = ParameterDirection.Output;
cmd.Parameters.Add(new OracleParameter("NEW_ID", OracleDbType.Decimal)).Direction = ParameterDirection.Output;

The values returned by

cmd.Parameters["NEW_ID"].Value.ToString()

and

cmd.Parameters["NUMFOUND"].Value.ToString()

get swapped, although running the procedure through the VS2008 Server Explorer returns correct data.

Why is this?

+4  A: 

I'm not an Oracle buff, so I can't verify - but it sounds like they are being passed by position (rather than passed by name). The moral equivelent to:

EXEC SomeProc 'Foo', 'Bar'

instead of:

EXEC SomeProc @arg1='Foo', @arg2='Bar'

This isn't hugely uncommon - for years (in the COM days) a lot of my code had to work with a pass-by-position ADODB driver.

In this case, the name that you give serves only as a local key to lookup the value from the collection collection. You can verify easily by inventing a name:

cmd.Parameters.Add(new    OracleParameter("BANANA", ...
cmd.Parameters.Add(new    OracleParameter("GUITAR", ...
...
cmd.Parameters["BANANA"].Value.ToString()
cmd.Parameters["GUITAR"].Value.ToString()

If the above runs without error, it is passing by position. And it they are passed by position... then simply add them in the right order ;-p And never add new parameters except at the end...

Marc Gravell
So they're being passed by position, though pass-by-name would be much more useful.
JC
+2  A: 

Not an answer to the question but you can use 'insert ... returning ... into ' in stead of select bgt_sequence.currval from dual, for example:

begin
  insert into test (id)
  values(test_seq.nextval)
  returning id into p_id;
end;

See http://www.adp-gmbh.ch/ora/sql/insert_into_x_returning_y.html

tuinstoel
+3  A: 

You can probably set the BindByName parameter on the OracleCommand object. This works for straight SQL queries with parameters, I've not tried it with stored procedures but it would be logical...

cmd.BindByName = true;
Marc
This is the real answer. Should be accepted.
John Gietzen