Getting strong-typed list of derived items

Hi all,
I’m looking for a way to get a list of derived items using their base abstract class as generic type.
Let’s say I have:

public abstract class BaseItem
{
  public string PropCommon { get; set; }
}

public class ChildItem1 : BaseItem
{
  public string Prop1 { get; set; }
}

public class ChildItem2 : BaseItem
{
  public string Prop2 { get; set; }
}

I’d want to read a collection of heterogeneous BaseItem objects using something like:

var queryRes = await collection.GetAsync(id, new GetOptions().CancellationToken(cancellationToken));
return queryRes.ContentAs<BaseItem>();

or

var queryRes = await bucket.Cluster.QueryAsync<T>(query);

In Newtonsoft there is the TypeNameHandling settings
In MongoDB there is the BsonKnownTypes attribute to decorate the base class with.

Is there any similar in Couchbase .NET SDK?

You can try to configure a transcoder with JSON Serializer which makes use of TypeNameHandling.

var serializer = new DefaultSerializer(
   deserializationSettings: new JsonSerializerSettings { TypeNameHandling = ... },
   serializerSettings: new JsonSerializerSettings { });

var transcoder = new JsonTranscoder(serializer);

var options = new GetOptions()
  .Transcoder(transcoder)
  .CancellationToken(cancellationToken);

var queryRes = await collection.GetAsync(id, options);

More info about transcoders and serializers can be found here: Transcoders & Non-JSON Documents | Couchbase Docs

2 Likes

If you would like to enable it globally, you may also configure the default serializer during bootstrap.

services.AddCouchbase(options => {
    Configuration.GetSection("Couchbase").Bind(options);

    options.WithSerializer(new DefaultSerializer(
        deserializationSettings: new JsonSerializerSettings { TypeNameHandling = ... },
        serializerSettings: new JsonSerializerSettings { TypeNameHandling = ... }));
});

Note that in this case, you’ll want to set TypeNameHandling on both serialization and deserialization. You may also want to use the CamelCasePropertyNamesContractResolver to be consistent with the default behavior.

Also, if you use @eugene-shcherbo example above, I would recommend saving the JsonTranscoder in a static field and reusing it across multiple GET operations for performance.

Thank you guys, I’m already preparing the code to use this method.

I use a main DAO class and registering it as a singleton in the app startup.
These are the readonly fields I set in the c’tor:

this.CommonGetOptions = new GetOptions().Transcoder(transcoder);
this.CommonQueryOptions = new QueryOptions();
this.CommonQueryOptions.Serializer = serializer;
this.CommonUpsertOption = new UpsertOptions().Transcoder(transcoder);

I plan to use these fields in every query.

It works, I’ve had to set

TypeNameHandling = TypeNameHandling.All

in order to use the abstract class in the generics query methods.

2 Likes