如何在标有[BsonExtraElements]

时间:2019-04-03 14:28:16

标签: c# mongodb serialization bson

更新

根据@aman的观察,这是有关我的应用程序业务逻辑的更多信息,“ ”可以使您从业务代码所依赖的字典中提取那些元素,并用它们的完好表达。定义的属性”

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

的业务逻辑

如果RiskColor大于1.5,则RiskColor应该为“红色”

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

基于以上定义,可以在运行时生成一个类,如下所示:

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

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


我有一些模型类(在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特定代码乱扔我的代码的解决方案。我希望有一个我错过的标志,或者希望以某种方式制定自定义约定以将其修复在驱动程序级别。

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

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 个答案:

答案 0 :(得分:0)

更新

  1. 由于您不希望业务逻辑了解数据库库使用的基础类型,因此我想您也已经为那些存在此类规定的值具体定义了用途,否则将不会很有道理。

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

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

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

  1. 另一种方法是按照本answer和本answer
  2. 中的描述,使用基于自定义类型的映射

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

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

Decimal128 value = 2.4M;

decimal result = (decimal)value;

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

BsonDecimal128 value = new BsonDecimal128(2.4M);

decimal result = value.AsDecimal;