I am helping to write a C# application to analyse financial data. Internally all the numbers are stored as decimal, however when we persist them to our mongodb database, we would like them to be stored as doubles, rather than strings.
I know I can do this for individual fields by applying the [BsonRepresentation(BsonType.Double)]
attribute to each decimal field, but I keep forgetting when adding new decimal values.
Is there any way of making this the default representation for all decimal numbers?
You can see my pull request for a sample of a convention to do this
https://github.com/mongodb/mongo-csharp-driver/pull/175
Here's how you would register it:
var conventions = new ConventionPack
{
new DecimalRepresentationConvention(BsonType.Double)
};
ConventionRegistry.Register("decimalAsDouble", conventions, t => condition);
For they type condition, people usually check the namespace, if it's just your own types you are serializing, you could just return true to apply it to every type.
See more about conventions here:
http://docs.mongodb.org/ecosystem/tutorial/serialize-documents-with-the-csharp-driver/#conventions
For anyone coming to this question now, it's worth mentioning that since v3.4, Mongo now natively supports storing Decimal
values, which is the best way to serialize C# decimal
values since using Double
can result in loss of precision, which can be particularly problematic with financial data.
You can find information on how to do this here: How to use decimal type in MongoDB
Looks like I'm talking to myself, but it might help someone else...
Here is an easier way:
void Main()
{
BsonSerializer.RegisterSerializationProvider(new MyDecimalSerializer());
Console.WriteLine(new Test().ToJson(new JsonWriterSettings() { Indent = true }));
}
class MyDecimalSerializer : DecimalSerializer, IBsonSerializationProvider {
private IBsonSerializationOptions _defaultSerializationOptions = new RepresentationSerializationOptions(BsonType.Double);
public override void Serialize(
BsonWriter bsonWriter,
Type nominalType,
object value,
IBsonSerializationOptions options) {
if(options == null) options = _defaultSerializationOptions;
base.Serialize(bsonWriter, nominalType, value, options);
}
public IBsonSerializer GetSerializer(Type type) {
return type == typeof(Decimal) ? this : null;
}
}
Using the same Test class as my other answer above, this works.
For simplicity, I have made my decimal serializer an IBsonSerialisationProvider itself - in the Bson source code, that role is usually taken by a class that maintains a list of types and serializers that can handle them.
Based on @NikkiLocke answer, but working on newer versions of mongo c# driver:
public class BsonDecimalSerializer : DecimalSerializer, IBsonSerializationProvider
{
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, decimal value)
{
context.Writer.WriteDouble((double)value);
}
public override decimal Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
return (decimal)context.Reader.ReadDouble();
}
public IBsonSerializer GetSerializer(Type type)
{
return type == typeof(decimal) ? this : null;
}
}
And the serializer registration:
BsonSerializer.RegisterSerializationProvider(new BsonDecimalSerializer());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With