Как получить десятичное вместо десятичного128 в словаре, помеченном [BsonExtraElements] - PullRequest
0 голосов
/ 03 апреля 2019

Обновление

Вот еще некоторая информация о бизнес-логике моего приложения, основанная на замечании @ 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 голосов
/ 03 апреля 2019

Обновление :

  1. Поскольку вы не хотите, чтобы бизнес-логика узнавала о базовых типах, которые использует ваша библиотека базы данных, я полагаю, что у вас также естьКонкретно определенное использование для тех значений, для которых существует такое условие, в противном случае это не имело бы особого смысла.

    В таком случае у вас должна быть возможность извлечь те элементы из словаря, от которых зависит ваш бизнес-коди представить их своими четко определенными свойствами.На мой взгляд, это был бы самый чистый подход:

public decimal ValueThatMyBusinessCodeUses { get; set; }
Вы также можете рассмотреть возможность использования настраиваемого сериализатора для объектов словаря в глобальном масштабе:
BsonSerializer.RegisterSerializer<IDictionary<string, object>>(new CustomDictionarySerializer());

Что касается реализации сериализатора словаря, взгляните наДокументация MongoDB по Сериализация .

Другой подход заключается в создании настраиваемого отображения на основе типов, как описано в этом ответе и этом ответе

Существуют различные вспомогательные методыв библиотеке MongoDB, которая разрешает приведение между типами C # и типами классов BSON, которые использует MongoDB.

Если у вас есть значение на основе MongoDB.Bson.Decimal128, вы можете просто привести его к десятичному типу следующим образом:

Decimal128 value = 2.4M;

decimal result = (decimal)value;

Если у вас есть значение MongoDB.Bson.BsonDecimal128, вы можете сделать следующее:

BsonDecimal128 value = new BsonDecimal128(2.4M);

decimal result = value.AsDecimal;
...