Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB BsonSerializer.Deserialize and F#

Tags:

mongodb

f#

bson

The following snippet appears to serialize the record properly, but the deserialization sets the fields to their default values.

open MongoDB.Bson
open MongoDB.Bson.Serialization
open System

module BsonIssue = 

    type MyData =
        { 
            Id : ObjectId
            Time : DateTime
        }

    let serialize(data : MyData) =
        let doc = BsonDocument()
        BsonSerializer.Serialize<MyData>(new IO.BsonDocumentWriter(doc), data)
        doc

    let deserialize(doc : BsonDocument) =
        printfn "Attempting to deserialize %A" doc
        BsonSerializer.Deserialize<MyData>(doc)

    let data = { Id = ObjectId.GenerateNewId(); Time = DateTime.Now }
    printfn "The data: %A" data
    let serialized = serialize data
    printfn "After serialization: %A" serialized
    let deserialized = deserialize serialized
    printfn "After deserialization: %A" deserialized

Here is an example of the output:

The data:

{Id = 55de887754893731fceeef58;
 Time = 8/26/2015 11:48:07 PM;}
After serialization: seq [_t=MyData; _id=55de887754893731fceeef58; Time=2015-08-27T03:48:07.836Z]
Attempting to deserialize seq [_t=MyData; _id=55de887754893731fceeef58; Time=2015-08-27T03:48:07.836Z]
After deserialization: {Id = 000000000000000000000000;
 Time = 1/1/0001 12:00:00 AM;}

Thanks in advance.

like image 315
S. Albert Avatar asked Aug 27 '15 03:08

S. Albert


1 Answers

Add [<CLIMutable>] to your record:

[<CLIMutable>]
type MyData =
    { 
        Id : ObjectId
        Time : DateTime
    }

FSI session:

> let data = { Id = ObjectId.GenerateNewId(); Time = DateTime.Now };;    
val data : MyData = {Id = 55dea10c4bd766216837843d;
                     Time = 27.08.2015 07:33:00;}

> let serialized = serialize data;;    
val serialized : BsonDocument

> let deserialized = deserialize serialized;;    
val deserialized : MyData = {Id = 55dea10c4bd766216837843d;
                             Time = 27.08.2015 05:33:00;}

Do, however, notice that the record doesn't round-trip correctly, because the Time values differ - at least on my machine. The two-hour time difference seems explainable by the fact that I'm two hours ahead of UTC currently, so my guess is that the BSON (de)serializer interprets all DateTime values as UTC values.

You should address this issue by using DateTimeOffset instead:

[<CLIMutable>]
type MyData =
    { 
        Id : ObjectId
        Time : DateTimeOffset
    }

FSI session:

> let data = { Id = ObjectId.GenerateNewId(); Time = DateTimeOffset.Now };;    
val data : MyData = {Id = 55dea3534bd766216837843f;
                     Time = 27.08.2015 07:42:43 +02:00;}

> let serialized = serialize data;;    
val serialized : BsonDocument

> let deserialized = deserialize serialized;;    
val deserialized : MyData = {Id = 55dea3534bd766216837843f;
                             Time = 27.08.2015 07:42:43 +02:00;}

> data = deserialized;;
val it : bool = true
like image 96
Mark Seemann Avatar answered Oct 11 '22 18:10

Mark Seemann