Uploaded image for project: 'C# Driver'
  1. C# Driver
  2. CSHARP-1757

LINQ support for types with custom serialization

    • Type: Icon: New Feature New Feature
    • Resolution: Won't Do
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: 2.2.4, 2.3.0-beta1
    • Component/s: Serialization
    • None
    • Hide

      1. What would you like to communicate to the user about this feature?
      2. Would you like the user to see examples of the syntax and/or executable code and its output?
      3. Which versions of the driver/connector does this apply to?

      Show
      1. What would you like to communicate to the user about this feature? 2. Would you like the user to see examples of the syntax and/or executable code and its output? 3. Which versions of the driver/connector does this apply to?
    • None
    • None
    • None
    • None
    • None
    • None

      I am trying to implement suitable reference container for objects, located in separate collections. For example,

      //some interface to specify persistent objects with Id
      public interface IPersistentObject
      {
          long Id { get; }
      }
      
      //and two entities mapped to separate collections
      public class Sample: IPersistentObject
      {
          public long Id { get; set; }
      }
      
      public class SampleWithReference: IPersistentObject
      {
          public long Id { get; set; }
          public Ref<Sample> Parent { get; set; }
      }
      

      Using described entities.

      var sample = new Sample() {Id: 32412132};
      var sampleWithRef = new SampleWithReference() {Id: 5635634};
      sampleWithRef.Parent.Set(sample);
      //and save both objects
      

      It results in the following DB record for SampleWithReference object:

      {
        "Id": 5635634,
        "Parent": 32412132
      }
      

      The reference container itself:

      //here is the reference container
      public class Ref<T> : IPersistentObject, IEquatable<long>, IEqualityComparer<long> where T : IPersistentObject, new()
      {
          public long Id { get; private set; }
      
          private T _Object;
      
          public T Get()
          {
              return _Object;
          }
      
          public void Set(T value)
          {
              _Object = value;
              Id = value == null ? 0L : value.Id;
          }
          //IEquatable and IEqualityComparer memebers implementation here
      }
      

      And serializer for it:

      public class RefSerializer<T> : SerializerBase<Ref<T>> where T : IPersistentObject, new()
      {        
      	public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, Ref<T> value)
      	{
      		long v = value;
      		context.Writer.WriteInt64(v);
      	}
      	public override Ref<T> Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
      	{
      		var id = context.Reader.ReadInt64();
      		return new Ref<T>(id);
      	}
      }
      

      Everything works great except LINQ doesn't support join on the Ref<> properties.

      This code can't be compiled because of type mismatch. equals operator strictly requires the same arguments type on both sides of expression. Implementation of IEquatable<long> and implicit conversion operators doesn't help.

      from r in DB.Query<SampleWithReference>()
      join s in DB.Query<Sample>() on r.Parent equals s.Id
      select s;
      

      The following expression fails because it searches nonexistent path Parent.Id. Meanwhile the db document looks like this: {"Id": 5635634, "Parent": 32412132}.

      from r in DB.Query<SampleWithReference>()
      join s in DB.Query<Sample>() on r.Parent.Id equals s.Id
      select s;
      

      What I've tried:

      • IBsonDocumentSerializer implementation can't help.
      • LINQ extension methods are useless because all translator logic is hidden with internal modifier inside driver assembly.

      I'm looking for a way to make joins work respecting the provided serializer. It's vitally important for my project. I couldn't find a suitable way to hook LINQ logic.

      Any advice will be much appreciated.

            Assignee:
            james.kovacs@mongodb.com James Kovacs
            Reporter:
            kreig Vyacheslav Stroy
            Votes:
            1 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: