Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserialising polymorphic types with MongoDB C# Driver

Assume, I have a base class

public class Node{
    public ObjectId Id;
    public String nodeName;
    public ObjectId parentNode;
}

and 2 derived classes

public class PlotNode:Node{
    public ObjectId Id;
    public String plotDetail;
}

public class EndNode:Node{
    public ObjectId Id;
    public int resultCode;
}

Several objects of all 3 classes are serialized are in database.

And only data i have is a list of ObjectId's, and only thing known about these ids is that they are certain to be Node ids but it's not know whether they are Node,PlotNode or EndNode in deserialise time.

I am using this to deserialize:

var collection = db.GetCollection<Node>("nodes");
var query = Query<Node>.EQ(e => e.Id, id);
Node node = collection.FindOne(query);

And in the end i get Nodes, not actual PlotNodes or EndNodes.

How can i know if they are one of the derived types and get back a object of that type?

like image 845
Quad Avatar asked Sep 05 '13 17:09

Quad


1 Answers

Why do you have the same "public ObjectId Id;" in each derived class? It is not really good idea. It hides parent Id field.

To solve your problem you need to "register" your derived classes (like in any serialization/deserialization mechanism). There are 3 ways to do it:

  1. Declarative way - decorate base Node class with:

    [BsonKnownTypes(typeof(PlotNode), typeof(EndNode))]
    
  2. Generic way - when types are known at compile time:

    BsonClassMap.RegisterClassMap<PlotNode>();
    BsonClassMap.RegisterClassMap<EndNode>();
    
  3. Dynamic way - when types are unknown at compile time:

    BsonClassMap.LookupClassMap(typeof(PlotNode));
    BsonClassMap.LookupClassMap(typeof(EndNode));
    

  • Another suggestion - use LINQ instead of Query

    Node node = collection.AsQueryable().FirstOrDefault(n => n.Id == id);
    
like image 142
Pavlo Avatar answered Nov 14 '22 06:11

Pavlo