Oracle
 sql >> Base de données >  >> RDS >> Oracle

ODP.NET UPDATE... RETURNING INTO... plusieurs lignes, Type de paramètre

finalement, après des heures de recherche et de jeu avec du code, je suis arrivé aux conclusions suivantes (mis à part le mal de tête) :

j'ai obtenu ce que je voulais en utilisant la combinaison de

  1. un indice ici , qui suggérait d'envelopper l'instruction UPDATE..RETURNING dans un bloc PL/SQL anonyme (commencez par BEGIN et finissez par END ;) - cela s'est passé sans explication et je ne sais toujours pas exactement pourquoi le comportement est différent
  2. extrait de code dans la documentation Oracle sur OracleCommand, en particulier la partie sur la liaison PL /Tableaux associatifs SQL avec BULK COLLECT INTO (impossible de faire fonctionner la simple liaison de tableau ..):

try
{
    conn.Open();
    transaction = conn.BeginTransaction();

    cmd = new OracleCommand();
    cmd.Connection = GetConnection();

    cmd.CommandText =
        "BEGIN UPDATE some_table " +
        "SET status = 'locked', " +
        "    locked_tstamp = SYSDATE, " +
        "    user_name = '" + user + "' " +
        "WHERE rownum <= 4 " +
        "RETURNING id BULK COLLECT INTO :id; END;";

    cmd.CommandType = CommandType.Text;

    cmd.BindByName = true;
    cmd.ArrayBindCount = 4;

    p = new OracleParameter();
    p.ParameterName = "id";
    p.Direction = ParameterDirection.Output;
    p.OracleDbType = OracleDbType.Int64;
    p.Size = 4;
    p.ArrayBindSize = new int[] { 10, 10, 10, 10 };
    p.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
    cmd.Parameters.Add(p);

    int nRowsAffected = cmd.ExecuteNonQuery();

    // nRowsAffected is always -1 here
    // we can check the number of "locked" rows only by counting elements in p.Value (which is returned as OracleDecimal[] here)
    // note that the code also works if less than 4 rows are updated, with the exception of 0 rows
    // in which case an exception is thrown - see below
    ...
}
catch (Exception ex)
{
    if (ex is OracleException && !String.IsNullOrEmpty(ex.Message) && ex.Message.Contains("ORA-22054")) // precision underflow (wth)..
    {
        Logger.Log.Info("0 rows fetched");
        transaction.Rollback();
    }
    else
    {
        Logger.Log.Error("Something went wrong during Get : " + ex.Message);
        ret = null;
        transaction.Rollback();
    }
}
finally
{
    // do disposals here
}
...