简体   繁体   中英

Mongo C#Driver:Deserialize BsonArray

I have a document in mongodb that is structured similar to this:

{
    "_id":xxxxx,
    "business":[{
            "subBusiness":[{
                "subBusinessName":"Abusiness",
                "a":"aaaa"
            },{
                "subBusinessName":"Bbusiness",
                "b":"bbbbb",
                "c":"ccccc"
                }]
        }]
}

how to make a mapping class to serialize this document?

I also have a class defined to represent dimensions (the sub document from above)

class STObject{
    [BsonId]
    public ObjectId id{get;set;}
    [BsonElement("business")]
    public List<Business> BusinessList{get;set;}
}
class Business  {   
    [BsonElement("subBusiness")]
    public List<SubBusiness> SubBuiness { get; set; }
}
[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof(CSSubBusiness),typeof(ApproSubBusiness))]
public class SubBusiness {
    [BsonElement("subBusinessName")]
    public string SubBusinessName{get;set;}
}
public class AsubBusiness:SubBusiness{
    [BsonElement("a")]
    public string A{get;set;}   
}
public class BsubBusiness:SubBusiness{
    [BsonElement("b")]
    public string B{get;set;}
    [BsonElement("c")]
    public string C{get;set;}
}

how to query element "b" in class STObject?

In order to deserialize class hierarchy , document should contain type discriminator field, which tells which type of subclass should be instantiated. By default this field has name _t . But if you already have documents with schema as above and can't change it, then you should override discriminator convention which is used by Mongo.

Looks like you can use subBusinessName field as type discriminator for sub business types. In order to do that, you should remove this field from base type:

[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof(AsubBusiness), typeof(BsubBusiness))] // btw check types
public class SubBusiness
{        
}

And you should provide discriminator values for subtypes:

[BsonDiscriminator("Abusiness")] // provide discriminator value here
public class AsubBusiness : SubBusiness
{
    [BsonElement("a")]
    public string A { get; set; }
}

[BsonDiscriminator("Bbusiness")]
public class BsubBusiness : SubBusiness
{
    [BsonElement("b")]
    public string B { get; set; }
    [BsonElement("c")]
    public string C { get; set; }
}

And final step - create custom convention to make mongo look on this discriminator field for instantiating correct sub class type:

public class SubBusinessDiscriminatorConvention : IDiscriminatorConvention
{
    public string ElementName
    {
        get { return "subBusinessName"; }
    }

    public Type GetActualType(BsonReader bsonReader, Type nominalType)
    {
        var bookmark = bsonReader.GetBookmark();
        bsonReader.ReadStartDocument();
        var actualType = nominalType;
        if (bsonReader.FindElement(ElementName))
        {
            var discriminator = (BsonValue)BsonValueSerializer.Instance.Deserialize(bsonReader, typeof(BsonValue), null);
            actualType = BsonSerializer.LookupActualType(nominalType, discriminator);
        }
        bsonReader.ReturnToBookmark(bookmark);
        return actualType;
    }

    public BsonValue GetDiscriminator(Type nominalType, Type actualType)
    {
        var classMap = BsonClassMap.LookupClassMap(actualType);
        return classMap.Discriminator;
    }
}

Now set this convention for your base type serialization:

BsonSerializer.RegisterDiscriminatorConvention(typeof(SubBusiness), 
    new SubBusinessDiscriminatorConvention());

And you can serialize and deserialize documents in your exact format.

UPDATE: Querying:

var collection = test.GetCollection<STObject>("collectionName");
var sto = collection.FindOne(Query.EQ("_id", new ObjectId("xxxxx")));
var businessList = sto.BusinessList.FirstOrDefault();
var bsub = businessList.SubBuiness.OfType<BsubBusiness>().FirstOrDefault();
var b = bsub.B; // returns bbbbb

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM