Azure / azure-cosmos-dotnet-v3

.NET SDK for Azure Cosmos DB for the core SQL API
MIT License
737 stars 493 forks source link

Support LINQ querying for records #3728

Open onionhammer opened 1 year ago

onionhammer commented 1 year ago

Is your feature request related to a problem? Please describe. Currently when invoking Select() for records, an exception is thrown

"Constructor invocation is not supported., Windows/10.0.19045 cosmos-netstandard-sdk/3.29.4"

Describe the solution you'd like Support constructors to select the members specified in constructors and let the deserializer handle the rest.

Describe alternatives you've considered There are no alternatives except to not use records or not use LINQ.

Additional context Example:

// record
record UserRecord(string Id)
{
    public string? Name { get; set; }
}

// query:
query.Select(x => new UserRecord(x.id, x.Name));

could result in

SELECT c.id as Id, c.Name
FROM c

which yields

[
   { "Id": "12345", "Name": "Joe" }
]

and skips potentially large JSON properties

adityasa commented 1 year ago

No committed plans to address this as of now.

bartelink commented 6 months ago

There are no alternatives except to not use records or not use LINQ.

@onionhammer in your specific case, you should be able to do query.Select(x => new { id = x.id; x.Name}) and then map that to your record (after you materialize the result against that anonymous type though?


In case this does ever get looked at... I'm trying to do the moral equivalent of this in F#, which is to do query.Select(x => {| id = id = x.id; Name = x.Name |}). This maps to a similar anonymous record type as C# anonymous type expressions. Sadly it currently yields me Microsoft.Azure.Cosmos.Linq.DocumentQueryException: Constructor invocation is not supported

I have a disgusting workaround: https://stackoverflow.com/a/78206722/11635, but ideally the LINQ support could desugar the object creation into an equivalent SELECT as the C# anonymous type expression does.

Basically my ask is the same as the OP: object construction expressions like this should map to JSON projections, and then it should be down to the caller to ensure that the JSON object that comes back can be deserialized to the Result type of the Expression