"ORA-03115: unsupported network datatype or representation" when trying to to fill DataSet

I'm trying to fill a DataSet object with an OracleCommand object, I just started using Oracle, I've using SQL Server all my life. On my NET console project I added the NuGet Oracle.ManagedDataAccess package and changed Sql objects to Oracle. Like: SqlConnection to OracleConnection. In SQL Server it works perfectly, but in Oracle it gives me this error I don't really understand what it means.

I changed SqlConnection to OracleConnection and SqlCommand to OracleCommand

also

command.Parameters.AddWithValue("@" + parameters[i], values[i] ?? DBNull.Value);

to

command.Parameters.Add(parameters[i], values[i] ?? DBNull.Value);
command.Parameters[i].Value = values[i];

Because AddWithValue doesn't exist on OracleCommand

This is the method that gets the data from the db.

        private void GetData(string storedProcedure, IReadOnlyList<string> parameters, IReadOnlyList<object> values)
        {
            using (var connection = new OracleConnection(_connectionString))
            {
                using (
                    var command = new OracleCommand(storedProcedure, connection)
                    {
                        CommandType = CommandType.StoredProcedure
                    })
                {
                    if (parameters != null)
                        for (var i = 0; i < parameters.Count; i++)
                        {
                            command.Parameters.Add(parameters[i], values[i] ?? DBNull.Value);
                        }
                    var ds = new DataSet();
                    connection.Open();
                    new OracleDataAdapter(command).Fill(ds);
                    _data = ds.Tables;
                    connection.Close();
                }
            }
        }

These are the parameters im using.

            var db = new Connector.Provider("AIA.GET_DATA",
                new[]{
                    "Test1",
                    "Test2",
                    "Test3",
                    "Test4"},
                new object[]{
                    1,
                    2,
                    3,
                    null});

And this is the stored procedure.

  PROCEDURE GET_DATA(
    Test1           in NUMBER,
    Test2           in NUMBER,
    Test3           in NUMBER,
    Test4           in NUMBER,
    TestOut        out SYS_REFCURSOR
    );

On the constructor of Provider it gets the connection string and uses method GetData.

It fails on:

new OracleDataAdapter(command).Fill(ds);

Oracle.ManagedDataAccess.Client.OracleException: 'ORA-03115: unsupported network datatype or representation'

Again, this works perfectly on SQL Server.

Any help is appreciated, at least, what does this error message means.


EDIT:

Thank you Luke Woodward, that was very helpful. So there was a problem with the OUT parameter, but also with the type of the parameters I was sending. So that solves the problem.

Anyway, I ended up with this new method. Which is working fine, except with nulls.

    private void GetData(string storedProcedure, IReadOnlyList<string> parameters, IReadOnlyList<object> values, IReadOnlyList<string> cursors)
    {
        using (var connection = new OracleConnection(_connectionString))
        {
            using (
                var command = new OracleCommand(storedProcedure, connection)
                {
                    CommandType = CommandType.StoredProcedure
                })
            {
                if (parameters != null)
                    for (var i = 0; i < parameters.Count; i++)
                    {
                        var parameter = new OracleParameter();
                        parameter.ParameterName = parameters[i];
                        if (values[i] is Enum)
                            parameter.Value = (int)values[i];
                        else
                            parameter.Value = values[i];

                        if (cursors != null && cursors.Contains(parameter.ParameterName))
                        {
                            parameter.Direction = ParameterDirection.Output;
                            parameter.OracleDbType = OracleDbType.RefCursor;
                        }
                        else
                        {
                            parameter.OracleDbType = GetOracleType(values[i]);
                        }
                        command.Parameters.Add(parameter);
                    }

                var ds = new DataSet();
                connection.Open();
                new OracleDataAdapter(command).Fill(ds);
                _data = ds.Tables;
                connection.Close();
            }
        }
    }

In Sql I could use DBNull.Value, but in Oracle I need to define OracleDbType, which is anonoying since this method worked for any object, not caring about the type, now I still don't know how to fix it to make it work with any object in Oracle. But that could be considered offtopic, this question could be marked as answered.

Upvotes: 1

Views: 2062

Answers (1)

Luke Woodward
Luke Woodward

Reputation: 64949

You need to add an OracleParameter for the OUT parameter TestOut but you are not doing this.

Add these lines after the other lines that set up the parameters:

    var outParam = new OracleParameter("TestOut", OracleDbType.RefCursor, ParameterDirection.Output);
    command.Parameters.Add(outParam);

You will then need to execute the command separately rather than pass the command to the OracleDataAdapter. Do this by adding the line

    command.ExecuteNonQuery();

immediately after the two that add outParam.

Finally, fill the dataset from the ref cursor in the OUT parameter by replacing the line

    new OracleDataAdapter(command).Fill(ds);

with

    new OracleDataAdapter().Fill(ds, (OracleRefCursor)outParam.Value);

Incidentally, I got a different error when I ran your code. I got the error PLS-00306: wrong number or types of arguments in call to 'GET_DATA'.

Upvotes: 1

Related Questions