Search code examples
c#mongodbasp.net-web-apimongodb-.net-driver

Converting BsonObjectId when getting record in C# from MongoDB


I have just started playing around with MongoDB today and have added a few records to my database and now would like to read them in C#.

Here is my C# object :

public class Team
{
    public string Id { get; set; }
    public string TeamId { get; set; }
    public string TeamName { get; set; }
    public string BadgeSmall { get; set; }
    public string BadgeLarge { get; set; }
    public string TeamImage { get; set; }
    public string Formation { get; set; }
}

And here is my code where I am reading from the database and converting to my object :

public IEnumerable<Team> GetTeams()
    {
        List<Team> model = new List<Team>();
        var teams = mongoDatabase.GetCollection("Teams").FindAll().AsEnumerable();

        model = (from team in teams
                 select new Team
                 {
                     Id = team["_id"].AsString,
                     TeamId = team["TeamId"].AsString,
                     TeamName = team["TeamName"].AsString,
                     BadgeSmall = team["BadgeSmall"].AsString,
                     BadgeLarge = team["BadgeLarge"].AsString,
                     TeamImage = team["TeamImage"].AsString,
                     Formation = team["Formation"].AsString,
                 }).ToList();
        return model;
    }

But the error I get is as follows :

Unable to cast object of type 'MongoDB.Bson.BsonObjectId' to type 'MongoDB.Bson.BsonString'.

It is a simple beginner's question but a bit of googling has not given me a working answer. How do I convert the BsonObjectId to a string, or am I going about this the wrong way?

EDIT :

This is the solution I went with, which is partly taken from the answer by mnemosyn:

[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }

public MongoCursor<Team> GetTeams()
        {
            MongoCursor<Team> m = mongoDatabase.GetCollection<Team>("Teams").FindAll();

            return m;
        }

Solution

  • Well, your Id is a string. Whether that is a good idea is a matter of philosophy almost. I don't think that it makes sense to be independent of the database since your data structure will be tied to the database anyway.

    MongoDB will try to instantiate objects of type Team, so, there's no need to manually map all the data to instances of Team - the Mongo driver does that for you. This code should do it:

    public class Team
    {
        public ObjectId Id { get; set; }
        public string TeamId { get; set; }
        public string TeamName { get; set; }
        public string BadgeSmall { get; set; }
        public string BadgeLarge { get; set; }
        public string TeamImage { get; set; }
        public string Formation { get; set; }
    }
    
    public MongoCursor<Team> GetTeams()
    {
        return mongoDatabase.Provider.GetCollection<Team>("Teams").FindAll();
    }
    

    Note that I'm retuning a MongoCursor, not an IEnumerable. That is somewhat obtrusive, because it makes large parts of the code depend on the MongoDB driver, but bear in mind that the two following statements will have VERY different performance characteristics:

    MongoCursor<Team> teams = GetTeams();
    
    // asks MongoDB for the count(), takes milliseconds:
    teams.Count(); 
    
    // calls the IEnumerable extensions method and will actually 
    // deserialize every Team object in the database(!), taking milliseconds
    // per batch of teams. On a large collection, this can take hours:
    ((IEnumerable)teams).Count();
    

    Hence, returning IEnumerable<> can have adverse effects on your performance. Be sure you known what method you're calling.