I don't know anything about ODP.net, but why concatenate all the record identifiers into a CSV string?
A better approach may be to create an array parameter in your procedure and pass an array of identifiers in. I guess it depends on where you get your list of identifiers from and whether they start off as an array or CSV string?
Here is an example of using an array type and joining that to your query without using a temporary table (you could do something similar with an IN list but its harder to bind):
create or replace type my_test_type as object (id integer);
create or replace type my_test_type_a as table of my_test_type;
create or replace procedure my_test_proc(i_ids in my_test_type_a)
is
begin
for row in (
select a.l from
(
select level l from dual connect by level <= 10
) a, table(i_ids) b
where a.l = b.id
) loop
dbms_output.put_line(row.l);
end loop;
end;
/
Note that the query in the test procedure used the 'table' function to turn the passed in array into a table in the query you can actually join other real tables to.
Also not that the subquery 'a', uses a trick to create a fake test table that contains 10 rows with values from 1 to 10 (this is just test data to prove this works).
Using the following block, we can test the code works:
declare
v_id my_test_type;
v_ids my_test_type_a;
begin
v_id := my_test_type(1);
v_ids := my_test_type_a();
for i in 1.. 5 loop
v_id := my_test_type(i);
v_ids.extend;
v_ids(i) := v_id;
end loop;
my_test_proc(v_ids);
end;
/
So long as dbms_output is on, this should print 1 - 5, as the test data table is joined with your array!