如何在标有 [BsonExtraElements] 的字典中获取 Decimal 而不是 Decimal128

How to get Decimal instead of Decimal128 in a dictionary marked with [BsonExtraElements]

更新

根据@aman 的观察 "it should be possible for you to pull out those elements from the dictionary that your business code depends on and have them represented by their well-defined properties".

,这里有一些关于我的应用程序业务逻辑的更多信息

应用程序的相关部分是(金融)产品的注册。该应用程序允许高级用户在产品上定义其他字段,还可以定义有限的业务逻辑。例如。他们可能会定义一个名为 RiskValuedecimal 类型的字段和一个 RiskColor 类型的 string 以及一段可以说

的业务逻辑

如果 RiskColor 大于 1.5,则 RiskColor 应为 "Red"

现在,此业务逻辑需要能够将 RiskColor 转换为 decimal 才能执行比较,这就是问题所在。

根据上面的定义,可以在运行时生成一个 class,类似于:

public class Product 
{
    public decimal RiskValue { get; set; }
    public string RiskColor { get; set; }
    public void BusinessLogic( )
    {
        if( RiskValue > 1.5M)
            RiskColor = "Red";
    }

但我不确定是否要走那条路。


我有一些模型 classes(在 C# 中),其中某些属性在编译时未知。所以我有一个

[BsonExtraElements]
IDictionary<string,object> ExtraElements {get;}

(实际上 BsonExtraElements 是通过约定来的,但我认为这不重要)。

其中一些属性属于 System.Decimal 类型,例如

obj.ExtraElements["PropertyX"] = 1.000M;

当我将对象保存到 MongoDB 时,它会像这样序列化:

{
    ...
    "PropertyX" : NumberDecimal("1.000"),
}

这是我所期望的。

但是,当我将对象读回我的模型时,属性 的值是 MongoDB.Bson.Decimal128 类型而不是预期的 System.Decimal.

大多数应用程序(数据层除外)都不知道底层存储机制,这也是我通过约定而不是通过属性(包含我的模型的程序集)注册 [BsonExtraElements] 的原因没有对 MongoDB 驱动程序的引用)。我正在寻找一种解决方案,我不需要用 MongoDB 特定代码乱丢我的代码。我希望有一个我错过的标志,或者也许可以通过某种方式制定自定义约定以在驱动程序级别修复它。

现在我已经通过在名为 ExtraElementsDictionary 的 class 中实现 IDictionary<string,object> 并在每个操作上通过此方法传递值来解决问题:

private static object FixValue( object value )
{
    if( value == null ) return null;
    if( value.GetType( ).FullName == "MongoDB.Bson.Decimal128" )
    {
        return decimal.TryParse( value.ToString( ), out var dec ) ? dec : default;
    }
    return value;
}

我也考虑过在数据层做,比如

public MyModel GetMyModelById(string id) 
{
    // actual retrieval of object
    FixDecimal128(obj.ExtraElements);
    return obj;
}

但一定有更好的方法吗?

更新:

  1. 由于您不希望业务逻辑了解您的数据库库使用的基础类型,我想您也已经具体定义了那些存在此类规定的值的用途,否则这没有多大意义。

    在这种情况下,您应该可以从您的业务代码所依赖的字典中提取那些元素,并用它们定义明确的属性来表示它们。在我看来,这将是最干净的方法:

public decimal ValueThatMyBusinessCodeUses { get; set; }
  1. 您还可以考虑以全局应用的方式为字典对象使用自定义序列化程序,如:
BsonSerializer.RegisterSerializer<IDictionary<string, object>>(new CustomDictionarySerializer());

关于如何实现字典序列化程序,请查看 Serialization 上的 MongoDB 文档。

  1. 另一种方法是使用基于自定义类型的映射,如此 answer and this
  2. 中所述

MongoDB 库中有各种辅助方法,允许在 C# 类型和 MongoDB 使用的 BSON class 类型之间进行转换。

如果您有一个基于 MongoDB.Bson.Decimal128 的值,您可以简单地将其转换为十进制,如下所示:

Decimal128 value = 2.4M;

decimal result = (decimal)value;

如果您有一个基于 MongoDB.Bson.BsonDecimal128 的值,您可以执行以下操作:

BsonDecimal128 value = new BsonDecimal128(2.4M);

decimal result = value.AsDecimal;