有没有办法在 .NET 中区分 SQL Money 和 Decimal 类型?

Is there a way to differentiate between SQL Money and Decimal types in .NET?

MoneyDecimal SQL 类型在 .NET 中都被解释为 Decimal。有什么办法可以区分吗?我正在尝试正确格式化 Excel 电子表格,但不知道哪些字段应该格式化为货币,哪些应该是小数。例如:

+----------------+------------------+--------------+-----------------+
| Name (VarChar) | Weight (Decimal) | Cost (Money) | Inventory (Int) |
+----------------+------------------+--------------+-----------------+
| Widget         | 3.75             | 9.99         |              25 |
+----------------+------------------+--------------+-----------------+

上面的 headers 包括用于此问题目的的数据类型,并且 query 是从 table:

中选择的存储过程
var result = conn.Query<dynamic>(query, parameters, commandType: CommandType.StoredProcedure).ToList();

foreach (var pair in (IDictionary<string, object>)result[0]) {
  Console.WriteLine($"{pair.Key}: {pair.Value.GetType().Name}");
}

将导致:

Name: String
Weight: Decimal
Cost: Decimal
Inventory: Int32

我发现了这个 post:Money datatype and decimal type of SQL in .net 但不幸的是,我没有标准化的列名,因为这意味着将任何结果集转换成 Excel 电子表格。

我还考虑过在需要时将存储过程更改为 pre-pend 美元符号,但这样做的工作量要大得多,而且很可能会破坏其他功能。

是否有不同的方法来确定结果的 SQL 类型?

我之前 运行 遇到过类似的问题,我刚刚查询了来自 sys.columns INNER JOIN sys.types ON columns.user_type_id = types.user_type_id 的列。但看起来您正在使用存储过程。在 SQL Server 2012 及更高版本中,您可以使用 sys.dm_exec_describe_first_result_set_for_object(@object_id,1).

找到存储过程的元数据

我建议您在 SQL(用户定义的类型)中使用可编程性下的类型。

您可以创建一个类型,就像我们在 SQL 中创建 class 一样,它由名称、重量、成本和库存组成,并在返回这些值的过程中将它们添加到用户定义您刚刚创建的类型并将其作为集合发送。

并在 .Net 中创建一个包含相同属性(名称、重量、成本和库存)的 class 并在其中获取值。

这是我的解决方案...

我在 VS2019 中创建了一个 localdb(v11.0) ([TestDb].[dbo].[Table])。它有 3 列:

  • Id(整数)
  • 数字(小数(18))
  • 美元(钱)

这是我获取模式的代码,然后获取 ColumnName 及其 ProviderSpecificDataType:

    [TestMethod]
    public void GetProviderSpecificDataType()
    {
        using (SqlConnection connection = new SqlConnection("Server=(localdb)\v11.0;Integrated Security=true;"))
        {
            connection.Open();
            SqlCommand cmd = connection.CreateCommand();
            cmd.CommandText = "select * from [TestDb].[dbo].[Table]";
            SqlDataReader reader = cmd.ExecuteReader();
            DataTable table = reader.GetSchemaTable();

            var columnTypes = GetColumnTypes(table);

            Assert.AreEqual("SqlInt32", columnTypes["Id"]);
            Assert.AreEqual("SqlDecimal", columnTypes["Number"]);
            Assert.AreEqual("SqlMoney", columnTypes["Dollars"]);
        }
    }

    private Dictionary<string, string> GetColumnTypes(DataTable table)
    {
        Dictionary<string, string> data = new Dictionary<string, string>();

        foreach (DataRow row in table.Rows)
        {
            string columnName = row["ColumnName"].ToString();
            string dataType = ((Type)row["ProviderSpecificDataType"]).Name;

            data[columnName] = dataType;
        }

        return data;
    }

我通过了测试...希望这至少能帮到您。