2014-02-25 11 views
6

Ich helfe beim Schreiben einer C# -Anwendung zur Analyse von Finanzdaten. Intern werden alle Zahlen als Dezimalzahlen gespeichert. Wenn wir sie jedoch in unserer mongodb-Datenbank beibehalten, möchten wir, dass sie als Doppel und nicht als Zeichenfolgen gespeichert werden. Ich weiß, ich kann dies zu jedem Dezimalfeld das [BsonRepresentation(BsonType.Double)] Attribut durch die Anwendung für einzelne Felder tun, aber ich vergesse immer wieder, wenn neue Dezimalwerte hinzufügen.Einstellung der Standard-MongoDb/Bson-Darstellung für alle Dezimalstellen zum Verdoppeln

Gibt es eine Möglichkeit, dies zur Standarddarstellung für alle Dezimalzahlen zu machen?

+0

sehen, ob das hilft [vom Typ ‚System.Decimal‘ speichern als ‚String‘] (https://jira.mongodb.org/plugins/ servlet/mobile # issue/CSHARP-196) – Yev

+1

Unabhängig von Alternativen, würde ich empfehlen, für dieses Problem zu wählen: https://jira.mongodb.org/browse/SERVER-1393 ... die vollständige Unterstützung für Dezimalzahlen in einführen würde MongoDB anstatt sich auf Speicher zu verlassen, der die Genauigkeit verlieren könnte. – WiredPrairie

+0

OK, das habe ich gemacht. –

Antwort

1

Für jeden auf diese Frage jetzt kommt, ist es erwähnenswert, das seit v3.4, Mongo unterstützt jetzt nativ unterstützt Decimal Werte, die die beste Möglichkeit ist, C# decimal Werte zu serialisieren, da die Verwendung von Double Verlust der Präzision führen kann, die mit Finanzdaten besonders problematisch sein kann.

Hier finden Sie Informationen darüber, wie dies hier zu tun: How to use decimal type in MongoDB

3

Sie können meine Pull-Anforderung für eine Probe einer Konvention, dies zu tun

https://github.com/mongodb/mongo-csharp-driver/pull/175

Hier sehen Sie, wie Sie es registrieren würde:

var conventions = new ConventionPack 
{ 
    new DecimalRepresentationConvention(BsonType.Double) 
}; 
ConventionRegistry.Register("decimalAsDouble", conventions, t => condition); 

Für sie Zustand geben, die Menschen in der Regel überprüfen Im Namespace können Sie, wenn es sich nur um die eigenen Typen handelt, die Sie serialisieren, True zurückgeben, um sie auf jeden Typ anzuwenden.

Sehen Sie mehr über Konventionen hier:

http://docs.mongodb.org/ecosystem/tutorial/serialize-documents-with-the-csharp-driver/#conventions

+0

Danke, das ist eine richtige Antwort. Ich konnte keine Dokumentation über Konventionen finden, daher war ich ein wenig verloren. –

+0

Nun, ich habe gerade diesen Code aus meinem Test-LinqPad-Skript entfernt und das echte Projekt eingefügt, und es funktioniert nicht mehr. Die Konvention ist registriert, aber Apply wird nie aufgerufen :-( –

+0

Jetzt funktioniert es nicht einmal im LinqPad-Skript. –

0

ich eine Antwort haben, aber es ist nicht schön - bessere Vorschläge noch willkommen.

Wenn dieser Code vor jeder Serialisierung ausgeführt wird, serialisiert er alle angegebenen Typen als doubles. Es scheint jedoch nicht automatisch mit vom Dictionary abgeleiteten Typen zu funktionieren - sie müssen in den Konventionen einzeln enthalten sein, was fast so viel Arbeit wie das Dekorieren aller Eigenschaften mit BsonRepresentation-Attributen sein kann. Ebenso behandelt es keine Wörterbücher in anderen Wörterbüchern.

Hier ist mein Testcode:

void Main() { 
    var conventions = new ConventionPack(); 
    var representAsDouble = new RepresentationSerializationOptions(BsonType.Double); 
    var representArrayAsDouble = new ArraySerializationOptions(representAsDouble); 
    var representDictionaryAsDouble = new DictionarySerializationOptions(){ KeyValuePairSerializationOptions = new KeyValuePairSerializationOptions() { ValueSerializationOptions = representArrayAsDouble}}; 
    conventions.Add(new MemberSerializationOptionsConvention(typeof(decimal), representAsDouble)); 
    conventions.Add(new MemberSerializationOptionsConvention(typeof(decimal[]), representArrayAsDouble)); 
    conventions.Add(new MemberSerializationOptionsConvention(typeof(Dictionary<string, decimal[]>), representDictionaryAsDouble)); 
    conventions.Add(new MemberSerializationOptionsConvention(typeof(SortedDictionary<string, decimal[]>), representDictionaryAsDouble)); 
    conventions.Add(new MemberSerializationOptionsConvention(typeof(Test.DerivedDictionary), representDictionaryAsDouble)); 
    ConventionRegistry.Register("Serialize decimal as double", conventions, t => true); 
    Console.WriteLine(new Test().ToJson(new JsonWriterSettings() { Indent = true })); 

} 

class Test : DbObject { 
    public Test() { 
     Array = new decimal[2]; 
     Array[0] = 2; 
     Array[1] = 3; 
     Dict = new Dictionary<string, decimal[]>(); 
     Dict["test"] = Array; 
     Dict2 = new SortedDictionary<string, decimal []>(); 
     Dict2["test"] = Array; 
     Dict3 = new DerivedDictionary(); 
     Dict3["test"] = Array; 
     Dict4 = new Dictionary<string, DerivedDictionary>(); 
     Dict4["test"] = Dict3; 
    } 

    public decimal Field = 1; 

    public decimal [] Array; 

    public Dictionary<string, decimal[]> Dict; 

    public SortedDictionary<string, decimal[]> Dict2; 

    public DerivedDictionary Dict3; 

    public Dictionary<string, DerivedDictionary> Dict4; 

    public class DerivedDictionary : Dictionary<string, decimal[]> { 
    } 
} 
1

Sieht aus wie ich mir rede, aber es könnte jemand anderes helfen ...

Hier ist ein einfacher Weg:

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; 
    } 
} 

Mit der gleichen Test-Klasse wie meine andere Antwort oben funktioniert das.

Der Einfachheit halber habe ich meinen Dezimalserialisierer selbst zu einem IBsonSerialisationProvider gemacht - im Bson-Quellcode wird diese Rolle normalerweise von einer Klasse übernommen, die eine Liste von Typen und Serialisern verwaltet, die damit umgehen können.

+0

Ja, das scheint in Ihrem Fall ein guter Anruf zu sein – Wes

+0

Haben Sie noch eine andere Idee, nur den doppelten Code zu verwenden? – Wes

+0

Betrachtet es, aber es ist nicht wirklich in meinem Fall geeignet. Natürlich wäre das beste Ergebnis für Dezimalzahlen werden in Mongo korrekt unterstützt. –

1

Basierend auf @NikkiLocke Antwort, aber die Arbeit auf neueren Versionen von Mongo C# Treiber:

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; 
    } 
} 

Und der Serializer Anmeldung:

BsonSerializer.RegisterSerializationProvider(new BsonDecimalSerializer());