Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions Dapper/DbDecimal.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dapper
{
/// <summary>
/// This class represents a SQL Decimal (Numeric) type, it can be used if you need
/// to be consistent with query parameter sizes, usually by specifying Precision and Scale
/// values that match the type in the database.
/// </summary>
public sealed class DbDecimal : SqlMapper.ICustomQueryParameter
{
private const byte _defaultPrecision = 38;
private const byte _defaultScale = 8;

/// <summary>
/// The value to be inserted or updated in the database
/// </summary>
public decimal Value { get; set; } = default;

/// <summary>
///
/// </summary>
public byte Precision { get; set; } = _defaultPrecision;

/// <summary>
/// The number of decimal digits that are stored to the right of the
/// decimal point.
/// </summary>
public byte Scale { get; set; } = _defaultScale;

/// <summary>
/// The default constructor used when attaching the individual properties
/// of the parameter.
/// </summary>
public DbDecimal()
{ }

/// <summary>
/// The primary constructor. This is the constructor that should generally
/// be used to create the object because it accepts values for the properties
/// used in the 90% use-case.
/// </summary>
/// <param name="value">The value to be inserted or updated in the database</param>
/// <param name="precision">The maximum total number of decimal digits to be stored.</param>
/// <param name="scale">The number of decimal digits that are stored to the right of the decimal point.</param>
public DbDecimal(decimal value, byte precision, byte scale)
{
this.Value = value;
this.Precision = precision;
this.Scale = scale;
}

/// <summary>
/// Add the parameter to the command... internal use only
/// </summary>
/// <param name="command"></param>
/// <param name="name"></param>
public void AddParameter(IDbCommand command, string name)
{
bool add = !command.Parameters.Contains(name);

IDbDataParameter param;
if (add)
{
param = command.CreateParameter();
param.ParameterName = name;
}
else
{
param = (IDbDataParameter)command.Parameters[name];
}

#pragma warning disable 0618
param.Value = SqlMapper.SanitizeParameterValue(Value);
#pragma warning restore 0618
param.Precision = this.Precision;
param.Scale = this.Scale;
param.DbType = DbType.Decimal;

if (add)
{
command.Parameters.Add(param);
}
}

}
}
61 changes: 61 additions & 0 deletions tests/Dapper.Tests/MiscTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,67 @@ public async void SO35470588_WrongValuePidValue()
Assert.Equal(568, row.Value);
}

[Fact]
public void TestDbDecimal()
{
var obj = connection.Query("select sql_variant_property(@a, 'precision') as a_precision, sql_variant_property(@a, 'scale') as a_scale, " +
"sql_variant_property(@b, 'precision') as b_precision, sql_variant_property(@b, 'scale') as b_scale, " +
"sql_variant_property(@c, 'precision') as c_precision, sql_variant_property(@c, 'scale') as c_scale, " +
"sql_variant_property(@d, 'precision') as d_precision, sql_variant_property(@d, 'scale') as d_scale, " +
"sql_variant_property(@e, 'precision') as e_precision, sql_variant_property(@e, 'scale') as e_scale",
new
{
a = new DbDecimal { Value = 123456.78M, Precision = 9, Scale = 3 },
b = new DbDecimal { Value = 123456.78M, Precision = 18, Scale = 3 },
c = new DbDecimal { Value = 123456.78M, Precision = 27, Scale = 3 },
d = new DbDecimal { Value = 123456.78M, Precision = 36, Scale = 3 },
e = new DbDecimal { Value = 123456.78M },
}).First();

Assert.Equal(3, (int)obj.a_scale);
Assert.Equal(9, (int)obj.a_precision);

Assert.Equal(3, (int)obj.b_scale);
Assert.Equal(18, (int)obj.b_precision);

Assert.Equal(3, (int)obj.c_scale);
Assert.Equal(27, (int)obj.c_precision);

Assert.Equal(3, (int)obj.d_scale);
Assert.Equal(36, (int)obj.d_precision);

Assert.Equal(8, (int)obj.e_scale);
Assert.Equal(38, (int)obj.e_precision);
}

[Fact]
public void TestDbDecimalUsingParameterizedConstructor()
{
var obj = connection.Query("select sql_variant_property(@a, 'precision') as a_precision, sql_variant_property(@a, 'scale') as a_scale, " +
"sql_variant_property(@b, 'precision') as b_precision, sql_variant_property(@b, 'scale') as b_scale, " +
"sql_variant_property(@c, 'precision') as c_precision, sql_variant_property(@c, 'scale') as c_scale, " +
"sql_variant_property(@d, 'precision') as d_precision, sql_variant_property(@d, 'scale') as d_scale",
new
{
a = new DbDecimal(123456.78M, 9, 3),
b = new DbDecimal(123456.78M, 18, 3),
c = new DbDecimal(123456.78M, 27, 3),
d = new DbDecimal(123456.78M, 36, 3),
}).First();

Assert.Equal(3, (int)obj.a_scale);
Assert.Equal(9, (int)obj.a_precision);

Assert.Equal(3, (int)obj.b_scale);
Assert.Equal(18, (int)obj.b_precision);

Assert.Equal(3, (int)obj.c_scale);
Assert.Equal(27, (int)obj.c_precision);

Assert.Equal(3, (int)obj.d_scale);
Assert.Equal(36, (int)obj.d_precision);
}

public class TPTable
{
public int Pid { get; set; }
Expand Down