Mongodb - how to deserialze when a property has an Interface return type

让人想犯罪 __ 提交于 2020-01-03 20:58:49

问题


I'm attempting to avoid introducing any dependencies between my Data layer and client code that makes use of this layer, but am running into some problems when attempting to do this with Mongo (using the MongoRepository)

MongoRepository shows examples where you create Types that reflect your data structure, and inherit Entity where required. Eg.

[CollectionName("track")]
public class Track : Entity  
{
    public string name { get; set; }
    public string hash { get; set; }

    public Artist artist { get; set; }
    public List<Publish> published {get; set;}
    public List<Occurence> occurence  {get; set;}
}

In order to make use of these in my client code, I'd like to replace the Mongo-specific types with Interfaces, e.g:

[CollectionName("track")]
public class Track : Entity, ITrackEntity 
{
    public string name { get; set; }
    public string hash { get; set; }

    public IArtistEntity artist { get; set; }
    public List<IPublishEntity> published {get; set;}
    public List<IOccurenceEntity> occurence  {get; set;}
}

However, the Mongo driver doesn't know how to treat these interfaces, and I understandably get the following error:

An error occurred while deserializing the artist property of class sf.data.mongodb.entities.Track: No serializer found for type sf.data.IArtistEntity. ---> MongoDB.Bson.BsonSerializationException: No serializer found for type sf.data.IArtistEntity.

Does anyone have any suggestions about how I should approach this?


回答1:


Okay - so I found the answer to my own question - and thought I'd share in case anyone has a similar problem

The feature I was looking for was BsonClassMap.RegisterClassMap

This allows you to explicitly define which properties / fields of your domain classes should be serialized / deserialized (note it replaces any automapping - you need to define all fields / properties you wish to include). It resolved the issue of deserializing to a property with an Interface type with no further problems.

BsonClassMap.RegisterClassMap<Track>(cm =>
{
    cm.MapProperty<IArtistEntity>(c => (IArtistEntity)c.Artist);
    cm.MapProperty<List<IOccurenceEntity>>(c => (List<IOccurenceEntity>)c.Occurence);
    cm.MapProperty(c => c.hash);
    cm.MapProperty(c => c.name);
    cm.MapProperty(c => c.published);

});



回答2:


What I did was pretty simple, and I think it would help you out. I had the same question as some of the commenters on the previous answer, so I did a bit more testing on my own. This is working for me.

If you have a concrete type that you're using for the interfaces, you can manually register the serializer that's generated for the concrete type for the interface type.

So in your case.

    BsonSerializer.RegisterSerializer(
        typeof(IPublishEntity), 
        BsonSerializer.LookupSerializer<Publish>());

and

    BsonSerializer.RegisterSerializer(
        typeof(IOccurenceEntity), 
        BsonSerializer.LookupSerializer<Occurence>());

I think it's also important to mention that I'm also manually registering the class maps for my concrete types immediately before registering the serializers. I have tested this method without doing so. I'm not sure if LookupSerializer method would fail if you haven't already done this, but that would look something like this.

    BsonClassMap.RegisterClassMap<Publish>(cm => {
        cm.AutoMap();
    });

and

    BsonClassMap.RegisterClassMap<Occurence>(cm => {
        cm.AutoMap();
    });

Just a cautionary side note that may be worth mentioning, I have not seen this solution anywhere else. Not entirely sure why, but I'm usually a bit skeptical when something that is seemingly obvious doesn't show up on Google's radar anywhere. Hope this helps someone.



来源:https://stackoverflow.com/questions/13096395/mongodb-how-to-deserialze-when-a-property-has-an-interface-return-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!