Dapper icon indicating copy to clipboard operation
Dapper copied to clipboard

Failed to insert large size of string into oracle clob type.

Open caoyang1024 opened this issue 11 years ago • 23 comments
trafficstars

When I was trying to insert a large size of string into oracle clob type, I will see exception : Specified argument was out of the range of valid values.

caoyang1024 avatar Aug 06 '14 10:08 caoyang1024

I've had a similar case with Guids stored as Oracle RAW(16). Adding a TypeHandler<> seems to work for getting the data out of the DB, but the SetValue method does not get called when inserting.

IanLedzion avatar Aug 31 '14 13:08 IanLedzion

Same problem here. The exception is thrown by: Oracle.DataAccess.Client.OracleParameter.set_Size(Int32 value), that is called by dynamic method: ParamInfoec73d72f-a86e-4a1e-a7fe-ab4d77846ed0(IDbCommand , Object )

rms81 avatar Nov 22 '14 18:11 rms81

I solved in my project creating a custom query parameter, someting like this:

internal class OracleClobParameter : SqlMapper.ICustomQueryParameter
{
    private readonly string value;

    public OracleClobParameter(string value)
    {
        this.value = value;
    }

    public void AddParameter(IDbCommand command, string name)
    {

        // accesing the connection in open state.
        var clob = new Oracle.DataAccess.Types.OracleClob(command.Connection as Oracle.DataAccess.Client.OracleConnection);

        // It should be Unicode oracle throws an exception when
        // the length is not even.
        var bytes = System.Text.Encoding.Unicode.GetBytes(value);
        var length = System.Text.Encoding.Unicode.GetByteCount(value);

        int pos = 0;
        int chunkSize = 1024; // Oracle does not allow large chunks.

        while (pos < length)
        {
            chunkSize = chunkSize > (length - pos) ? chunkSize = length - pos : chunkSize;
            clob.Write(bytes, pos, chunkSize);
            pos += chunkSize;
        }

        var param = new Oracle.DataAccess.Client.OracleParameter(name, Oracle.DataAccess.Client.OracleDbType.Clob);
        param.Value = clob;

        command.Parameters.Add(param);
    }
}

And then using this parameter in my command:

connection.Execute("INSERT INTO MESSAGES VALUES (:id, :text)", new {id = 1, text = new OracleClobParameter("my large text") });

It's not a real solution, but works for me, :)

I hope this helps to create a real solution in a future.

miguelerm avatar Mar 18 '15 19:03 miguelerm

+1 for @miguelerm as his solution also worked for me

Boggin avatar Feb 26 '16 14:02 Boggin

Thanks @miguelerm, this worked for us too :)

rpbeier avatar Sep 27 '16 22:09 rpbeier

Thanks @miguelerm this solution worked for me

warnee avatar Jan 11 '17 01:01 warnee

I am using dynamic parameters and it does not work for me:

    var itemParams = new DynamicParameters(doc);
    itemParams.Add("LargeText",new OracleClobParameter(doc.LargeText));

It is working I had to change paramter name.

waldimen avatar Dec 13 '17 11:12 waldimen

well... what happened? an exception (and if so: exactly what)? or was the data truncated? not sent at all?

On 13 Dec 2017 11:53 a.m., "waldimen" [email protected] wrote:

I am using dynamic parameters and it does not work for me:

var itemParams = new DynamicParameters(doc);
itemParams.Add("LargeText",new OracleClobParameter(doc.LargeText));

Any ideas how to make it work ?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/StackExchange/Dapper/issues/142#issuecomment-351369861, or mute the thread https://github.com/notifications/unsubscribe-auth/AABDsO3MqeYxCpnvON0FZM9OU8UIO42sks5s_7rJgaJpZM4CUlW3 .

mgravell avatar Dec 13 '17 13:12 mgravell

I have the same issue (.NET core) in March 2019. Are they planning to solve this issue?

AttilaDNagy avatar Mar 08 '19 15:03 AttilaDNagy

I have the same issue .

MetSystem avatar Aug 12 '19 04:08 MetSystem

The problem still happens on version 1.60.6 with oracle managed data access core (2.19.31). Thankfully, @miguelerm solution still works with adjusted namespaces.

diegosps avatar Sep 02 '19 18:09 diegosps

With Dapper.Oracle this worked for me:

var parameters = new OracleDynamicParameters();
parameters.Add("JSONDOCUMENT", saveRequest.JsonDocument, OracleMappingType.Clob, ParameterDirection.Input);

wast avatar Nov 27 '19 11:11 wast

With Dapper.Oracle this worked for me:

var parameters = new OracleDynamicParameters();
parameters.Add("JSONDOCUMENT", saveRequest.JsonDocument, OracleMappingType.Clob, ParameterDirection.Input);

Was the parameter string in C# with more than 4000 characters?

AttilaDNagy avatar Nov 27 '19 12:11 AttilaDNagy

Worked with more than 300.000 characters.

wast avatar Nov 30 '19 19:11 wast

I have the same issue . @mgravell

luoyanglihao avatar Dec 17 '19 12:12 luoyanglihao

@luoyanglihao did you try the Dapper.Oracle approach above? Oracle has so many non-standard things happening w.r.t. .NET, I'm leaning towards just recommending that library and not changing Dapper core to work around the issues...since they're doing a great job of it.

NickCraver avatar May 04 '20 02:05 NickCraver

Usage of DynamicParameters worked for us. (Dapper version 2.0.90)

var queryParams = new DynamicParameters(new  
{  
    SYSTEMID = SystemId,  
    KEYNAME = KeyName  
});  
queryParams.Add("TOKEN", value, DbType.String, size: 65536);
_connection.Execute(UPDATE_TOKEN, queryParams);

deepbluesky avatar Jun 23 '21 07:06 deepbluesky

Usage of DynamicParameters worked for us. (Dapper version 2.0.90)

var queryParams = new DynamicParameters(new  
{  
    SYSTEMID = SystemId,  
    KEYNAME = KeyName  
});  
queryParams.Add("TOKEN", value, DbType.String, size: 65536);
_connection.Execute(UPDATE_TOKEN, queryParams);

This works in Dapper v1.8.0 too. We can omit size param:

queryParams.Add("TOKEN", value, DbType.String);

sunghwan2789 avatar Jul 25 '21 13:07 sunghwan2789

I have same question

edobnet avatar Mar 16 '22 00:03 edobnet

Same for me.

FrameWork: .Net 6.0 Dapper: 2.0.123 Oracle.ManagedDataAccess.Core: 3.21.65

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. thrown if the data size exceeds 4Kb.

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. at Oracle.ManagedDataAccess.Client.OracleParameter.set_Size(Int32 value) at ParamInfoebf64429-6c5c-4a94-9646-cd34dfc8e77f(IDbCommand , Object ) at Dapper.CommandDefinition.SetupCommand(IDbConnection cnn, Action2 paramReader) at Dapper.SqlMapper.TrySetupAsyncCommand(CommandDefinition command, IDbConnection cnn, Action2 paramReader) at Dapper.SqlMapper.ExecuteImplAsync(IDbConnection cnn, CommandDefinition command, Object param)

Also @sunghwan2789's solution worked for me.

nkkarasu avatar May 25 '22 14:05 nkkarasu

Usage of DynamicParameters worked for us. (Dapper version 2.0.90)

var queryParams = new DynamicParameters(new  
{  
    SYSTEMID = SystemId,  
    KEYNAME = KeyName  
});  
queryParams.Add("TOKEN", value, DbType.String, size: 65536);
_connection.Execute(UPDATE_TOKEN, queryParams);

Thanks, this solution worked for me in Dapper 2.0.123 with .Net 6.0

MiddleKerb avatar Sep 05 '22 07:09 MiddleKerb

In fact using DynamicParameters solves the issue.

But I make use of anonymous parameters frequently, and unfortunately, using DynamicParameters does not allow me to retrieve the parameter name using the 'nameof' operator.

here is a sample:

public void SaveLog(Exception ex, string userId)
{
    var parameters = new
    {
        user = userId,
        message = ex.Message,
        stacktrace = ex.ToString(), //clob bigger than 4000. throws System.ArgumentOutOfRangeException
    };

    var sql = $@"INSERT INTO LOG (
                        ID_LOG, 
                        ID_USUARIO, 
                        STACKTRACE
                  ) VALUES (
                        SQ_ID_LOG.NEXTVAL, 
                        :{nameof(parameters.user)}, 
                        :{nameof(parameters.message)}, 
                        :{nameof(parameters.stacktrace)})";

    db.Execute(sql, parameters);
}

fsbflavio avatar Jul 22 '23 18:07 fsbflavio

Update for 2024 - .NET 6/8, Dapper 2.1.x - @miguelerm solution is working for me with minimal modification -

using Dapper;
using System.Data;

namespace MyNamespace;

internal class OracleClobParameter : SqlMapper.ICustomQueryParameter
{
    private readonly string value;

    public OracleClobParameter(string value)
    {
        this.value = value;
    }

    public void AddParameter(IDbCommand command, string name)
    {

        // accesing the connection in open state.
        var clob = new Oracle.ManagedDataAccess.Types.OracleClob(command.Connection as Oracle.ManagedDataAccess.Client.OracleConnection);


        // It should be Unicode oracle throws an exception when
        // the length is not even.
        var bytes = System.Text.Encoding.Unicode.GetBytes(value);
        var length = System.Text.Encoding.Unicode.GetByteCount(value);

        int pos = 0;
        int chunkSize = 1024; // Oracle does not allow large chunks.

        while (pos < length)
        {
            chunkSize = chunkSize > (length - pos) ? chunkSize = length - pos : chunkSize;
            clob.Write(bytes, pos, chunkSize);
            pos += chunkSize;
        }

        var param = new Oracle.ManagedDataAccess.Client.OracleParameter(name, Oracle.ManagedDataAccess.Client.OracleDbType.Clob);
        param.Value = clob;

        command.Parameters.Add(param);
    }
}```

Drwillard avatar Feb 11 '24 20:02 Drwillard