[CSHARP-4731] Support assigning List<T> value to IList<T> property in Select Created: 26/Jul/23  Updated: 28/Oct/23  Resolved: 03/Aug/23

Status: Closed
Project: C# Driver
Component/s: LINQ3
Affects Version/s: None
Fix Version/s: 2.21.0

Type: Improvement Priority: Unknown
Reporter: Robert Stam Assignee: Robert Stam
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Documentation Changes: Not Needed
Documentation Changes Summary:

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?


 Description   

The following query does not currently work:

var queryable = collection
    .AsQueryable()
    .Select(x => new P { IList = x.List })

where the classes are defined as follows:

private class Test
{
    public int Id { get; set; }
    [BsonRepresentation(BsonType.String)]
    public List<E> List { get; set; }
}
 
private class P
{
    public IList<E> IList { get; set; }
}
 
private enum E { A, B, C, D };



 Comments   
Comment by Shiya Kohn [ 24/Aug/23 ]

Is the detection of whether the server supports "aggregation style projections" done once per env, or once per client? We have 2 servers, one is our global server that tells use whether a given tenant exists, and then a server (a few of them) that holds per tenant data. I believe our central server is below the required version, whereas the per tenant servers are v4.4.

Comment by Shiya Kohn [ 24/Aug/23 ]

Our server does support "aggregation style projections" in `Find`. I understand the difficulty of navigating between translating to MQL, vs just detecting the visited properties and projecting them as a whole and handing off the rest of the expression to the client side, I just don't understand why V3 can't just attempt translating to MQL and fallback to client side if it encounters an unknown operation, I highly doubt that code consumers care whether their projection is fully server side or only partially server side. If I were you, I'd have a list of operations that get translated to MQL and hand everything else back to client side (I assume you already do this if the expression references static method calls, which probably should be extended to unsupported linq extensions)

Comment by Robert Stam [ 15/Aug/23 ]

Thanks for the additional information. I will investigate a more general fix that doesn't only apply to `IEnumerable`.

For the most part `Find` and `Aggregate` support the same projections. The main exceptions are if you are using a very old server version (old enough that it doesn't support "aggregation style projections" in `Find) or if your projection Expression contains constructs that can't be translated to MQL (LINQ2 supports "client side projections" and LINQ3 does not).

Comment by Shiya Kohn [ 14/Aug/23 ]

Spent way too long playing around with this. Here are my 2 cents.

  • There shouldn't be perfectly valid expressions that work only in the aggregate pipeline (IQueryable) but not in the find pipeline  (IFindFluent), and vice versa.
  • Why are lists as IList special, all types should support serializing as less specific types but not the other way around.
Comment by Shiya Kohn [ 14/Aug/23 ]

Further confusion is the difference between the `IFindFluent` translator vs the queryables. For example, we have been using v2.16.1 with V2 linq for a while, all projections we use thru `.Project` work as expected (derived types can be represented as their base in a projection), the queryable pipeline however, throws with the same error as you would get in v2.20.0 for lists as ilist. V3 works properly in v16 but breaks after.

Comment by Shiya Kohn [ 14/Aug/23 ]

This commit seems to be specific to enumerable types, whilst the bug seems to be a general problem for anything where the projected type is less specific than the declared type.

 

I can confirm that the behaviour was as expected (expressions that are type-safe at compile time should work) in older versions of V3

Comment by Githook User [ 03/Aug/23 ]

Author:

{'name': 'rstam', 'email': 'robert@robertstam.org', 'username': 'rstam'}

Message: CSHARP-4731: Support assigning List<T> value to IList<T> property in Select.
Branch: master
https://github.com/mongodb/mongo-csharp-driver/commit/03498514242482c83b47171d8d097ab2515cca2b

Generated at Wed Feb 07 21:49:11 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.