Using DBNull.Value with SqlParameter without knowing sqlDbType?

前端 未结 5 1308
有刺的猬
有刺的猬 2021-01-05 19:42

I\'m using a SqlParameter to pass in null values to a table for various columns that are nullable. The problem is that SqlParameter looks like it defaults to nv

5条回答
  •  清酒与你
    2021-01-05 20:14

    I'm dealing with a sort of in-house ORM that uses objects to generate parameters. Since they are essentially typeless when null it makes it difficult to differentiate the various SQL null types.

    DBNull.Value works for almost every SQL type, but it fails for a varbinary(max) column I'm using. Instead you must use SqlBinary.Null -- don't ask me why.

    I decided to use a special tagged value here to indicate when this column type should be used. Full except from our "ORM" below:

    using System.Data.SqlTypes;
    
    class MyModelType
    {
        public Guid ID { get; set; }
        public byte[] Data { get; set; }
    }
    
    static readonly object NullSqlBinary = new object();
    
    object SqlValueForObject(object val)
    {
        if (val == null)
        {
            val = DBNull.Value;
        }
        else if (val == NullSqlBinary)
        {
            val = SqlBinary.Null;
        }
        return val;
    }
    
    IDictionary Params(MyModelType x)
    {
        return new Dictionary
        {
            { "@ID", x.ID },
            { "@Data", x.Data ?? NullSqlBinary },
        };
    }
    
    private SqlCommand CreateCommand()
    {
        var cmd = Connection.CreateCommand();
        cmd.CommandTimeout = 60;
    
        return cmd;
    }
    
    SqlCommand CreateCommand(string sql, IDictionary values)
    {
        var cmd = CreateCommand();
        cmd.CommandText = sql;
        cmd.Transaction = GetCurrentTransaction();
    
        cmd.Parameters.Clear();
        if (values != null)
        {
            foreach (var kvp in values)
            {
                object sqlVal = SqlValueForObject(kvp.Value);
                cmd.Parameters.AddWithValue(kvp.Key, sqlVal);
            }
        }
        return cmd;
    }
    
    int Execute(string sql, IDictionary values)
    {
        using (var cmd = CreateCommand(sql, values))
        {
            return cmd.ExecuteNonQuery();
        }
    }
    
    void InsertMyModel(MyModelType obj)
    {
        DB.Execute(
            @"INSERT INTO MyTable (ID, Data)
            VALUES (@ID, @Data)", Params(obj));
    }
    

提交回复
热议问题