1

I am fairly new to mongodb and I am trying to query a collection with byte property but I am getting an invalid cast exception. To summarize,

public class MongoDbAddressCollection    
{
     private IMongoCollection<Addresses> collection = database.GetCollection<Addresses>("AddressCollection");
     public IEnumerable<Addresses> Where(System.Linq.Expressions.Expression<Func<Addresses, bool>> filter = null)
     {
         var items = collection.AsQueryable().Where(filter);
         if (items == null)
             return null;
         return items.ToList();
     }
}

public class Test
{
    public void DoSomthingWithAddresses()
    {
         MongoDbAddressCollection addressCollection=new MongoDbAddressCollection();
         //exception occurs in MongoDbAddressCollection.Where method when executing the ToList().
         List<Addresses> homeAddresses=addressCollection.Where(x=>x.AddressType==(byte)EnumAddressType.HomeAddress);
         foreach(var address in homeAddresses)
         {
            //do stuff
         }
    }
}

And the address entity is as following class

public class Address
{
    public Guid UserId { get; set; }
    public string Street { get; set; }
    public byte AddressType { get; set; }
    .....
}

public enum EnumAddressType
{
    HomeAddress=1,
    WorkAddress=2
}

Actually the issue seems to be a type mismatch between mongodb and .net, I can see that the AddressType for WorkAddress entities is 10 which is binary representation of 2. But, I cannot think of a solution other than changing all byte properties in all of our entities to int before I insert them to collections (we have lots of byte properties in different entities)... Or can this be fixed with a workaround in the query (linq where condition)?

Thanks in advanced.

Ahmet Keskin
  • 1,025
  • 1
  • 15
  • 25

1 Answers1

1

There is indeed a problem with the serialization of byte type. I think the fastest solution would be to change the type of AddressType property from byte to EnumAddressType

public class Address
{
    public Guid UserId { get; set; }
    public string Street { get; set; }
    public EnumAddressType AddressType { get; set; }
}

And write your filter without casting:

var filter = Builders<Address>.Filter
    .Where(x => x.AddressType == EnumAddressType.HomeAddress);

You can test your filter using this method:

public static BsonDocument RenderToBsonDocument<T>(FilterDefinition<T> filter)
{
    var serializerRegistry = BsonSerializer.SerializerRegistry;
    var documentSerializer = serializerRegistry.GetSerializer<T>();
    return filter.Render(documentSerializer, serializerRegistry);
}

The result

var json = RenderToBsonDocument(filter).ToJson();
// Result: { "AddressType" : 1 }

As an alternative approach, you can write your custom byte serializer and register it using:

BsonClassMap.RegisterClassMap<Address>(cm =>
{
    cm.AutoMap();
    cm.GetMemberMap(c => c.AddressType).SetSerializer(MyCustomByteSerializer.Instance);
});

You can see a sample serializer code here.

M. Mennan Kara
  • 10,072
  • 2
  • 35
  • 39
  • Thank you for the answer Mennan. Changing the property type to enum is not really an option because the property corresponds to a tinyint column in the database and the entity is auto generated... I tried the custom serializer and the data is fine in mongodb now but I am still getting an exception when I am executing the Where(filter).ToList() method. – Ahmet Keskin Mar 31 '16 at 05:24