couchbaselabs / Linq2Couchbase

A Language Integrated Query (LINQ) provider for the Couchbase .NET SDK
Apache License 2.0
94 stars 48 forks source link

Metadata Semantics Too Verbose #262

Open groogiam opened 5 years ago

groogiam commented 5 years ago

The semantics for retrieving metadata seem rather verbose. In order to populate a Document I have I have to call the Meta function several times.

db.Query<TestDataEntity>().Select(s => new Document<TestDataEntity>
            {
                Id = N1QlFunctions.Meta(s).Id,
                Cas = N1QlFunctions.Meta(s).Cas,
                Content = s
            }).First()

It really seems like there should be a way to just directly map the metadata to a Document or even better to properties on the POCO object. Something like the BsonIdAttribute in MongoDb.

brantburnett commented 5 years ago

@groogiam,

If your primary purpose is to support writing back to the document, I'd recommend using change tracking. This automates the Id and Cas handling for you. https://github.com/couchbaselabs/Linq2Couchbase/blob/master/docs/change-tracking.md

If you need more fine-grained control, I normally use anonymous objects instead of the Document class. Then you can collect the metadata using a single call.

db.Query<TestDataEntity>().Select(s => new
            {
                Meta = N1QlFunctions.Meta(s),
                Content = s
            }).First()

That said, selecting directly into a Document class is an interesting idea. An extension method should be able to accomplish that pretty easily:

public static class Extensions
{
    public static IQueryable<Document<T>> SelectDocument<T>(this IQueryable<T> source)
    {
        return source.Select(p => new Document<T>
            {
                Id = N1QlFunctions.Meta(p).Id,
                Cas = N1QlFunctions.Meta(p).Cas,
                Content = p
            });
    }
}

Then you could easily repeat the process without as much lift:

db.Query<TestDataEntity>().SelectDocument().First()

Let me know how that works for you and maybe we'll make it a built-in extension.

groogiam commented 5 years ago

I'm not sure that the extension method will work. Won't the provider throw a not supported exception because as it will try to translate the function to N1QL?

brantburnett commented 5 years ago

It shouldn’t because it’s internally using Select to alter the Queryable, and it’s not within a lambda itself.

groogiam commented 5 years ago

I think there is an issue with the Cas data types. Document uses ulong while the N1QlFunctions.Meta uses a double for some reason. Converting in the extension method throws an unsupported exception. Is there a reason why the Cas is a double in Linq2Couchbase?

jeffrymorris commented 5 years ago

@groogiam -

Yeah, that seems like a bug:

https://github.com/couchbaselabs/Linq2Couchbase/blob/master/Src/Couchbase.Linq/Metadata/DocumentMetadata.cs#L16

Cas should be a ulong - unless @brantburnett has some more insight?

brantburnett commented 5 years ago

@jeffrymorris

I did some digging, and it appears to be a mistake I made in the early days that lives on. I can't recall any specific reason I would have chosen double instead of ulong.

Our problem now is that fixing it will be a breaking change, requiring us to bump to 2.x. I suppose we could do something with an additional property with some typecasting? But seems messy.