I am having custom Id classes, for example TestDocumentId which ToString generates string in the form “testdocument-some-id”
The document class example:
public class TestDocument
{
public TestDocumentId Id {get; set;}
public string Name {get; set;}
}
Now, executing
bucketContext.Query<TestDocument>().Where( t => t.Id == TestDocumentIdConst.ToString() )
generates correct query:
SELECT RAW Extent1 FROM test as Extent1 WHERE (Extent1.type = ‘TestDocument’) AND (Extent1.id = ‘testdocument-f1514cc6-dc70-4e1d-9b53-3c506e58c881’)
But the query without .ToString() call generates invalid where clause (wthout ’ marks):
SELECT RAW Extent1 FROM test as Extent1 WHERE (Extent1.type = ‘TestDocument’) AND (Extent1.id = testdocument-f1514cc6-dc70-4e1d-9b53-3c506e58c881)
I think this is due to the fact that that VisitConstant function inside N1QlExpressionTreeVisitor class just calls ToString() method for namedParameters that are custom/unknown types.
I have found similar issue for Guids that has been solved:
Any workaround for this problem without actually changing Linq2Couchbase library?
Can you provide the C# syntax that you’re using that’s generating the incorrect syntax? Also, are you using custom equality methods on the TestDocumentId class?
In general, LINQ providers don’t support overrides of the equality operator. At least, I don’t know of one that does, but I could be wrong. Since the .Equals function isn’t an Expression tree, there’s no way to know what magic is happening inside it to replicate that in the query.
I would recommend looking at using the new support for custom serialization attributes. You could apply a [JsonConverter(…)] attribute to the TestDocumentId class, and combine that with a change to how the constant is then serialized in the query.
This is new functionality, just added in the last couple of weeks, you’d probably be the first one to use it outside of the internal usage inside Linq2Couchbase. If you do use it, I’d love to get feedback on how it goes. I’m also happy to help.
However, none of the methods inside TestDocumentIdSerializationConverter are being called when expression tree is being created. I was expecting RenderConvertedConstant method to be called.
Apparently, the current logic is only finding the JsonConverter when applied to the property on the POCO, not when applied to the TestDocumentId class. Once I moved it to the ID property, it worked.
I’d also point out that the custom serializer inheriting from DefaultSerializer shouldn’t be necessary, and that the document type filter is probably better applied as a [DocumentTypeFilter(…)] attribute on the POCO.
I know that both custom serializer and attribute are not needed. It was more of trying every possible solution.
Would it be possible to have alternative approach for this situation other than applying attributes to POCO? I have situation where my POCOs are in external lib and it is not convenient to change then. Seems to me that having custom serializer (in my case inherited from DefaultSerializer) and custom serialization converter should be enough for Linq2Couchbase to understand how to generate underlying queries.
You are correct, using a custom serializer should be sufficient as well. The key is that Newtonsoft.Json tells us that the converter is in use on a specific property.
Of course, this logic clearly needs some tweaking. When I work on it, I’ll try to make sure it picks up converters added to the global serialization settings as well.