[CSHARP-1582] Linq queries are getting the right result, but hydrates more elements than expected. Created: 29/Feb/16 Updated: 02/Mar/16 Resolved: 02/Mar/16 |
|
| Status: | Closed |
| Project: | C# Driver |
| Component/s: | API, Performance |
| Affects Version/s: | 2.2.2, 2.2.3 |
| Fix Version/s: | None |
| Type: | Improvement | Priority: | Major - P3 |
| Reporter: | Juan Antonio | Assignee: | Robert Stam |
| Resolution: | Done | Votes: | 0 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Description |
|
Hi all, Using c# driver through Linq expressions, we've noticed that many objects are hydrated when using AsQueryable() + Linq expresion even though the query returns one result. ... By the other hand, if we use Eq method, the behavior is the expected: there is only one object hydrated. ... Is that te implemented behaviour of the driver using Linq? Many thanks! |
| Comments |
| Comment by Robert Stam [ 02/Mar/16 ] | |||||||||||||||||||||||||||||||||
|
As Craig predicted I can reproduce what you observed if I use a Func instead of an Expression:
If I use the first (commented out) predicate then many extra instances are hydrated. If I use the second Expression based form then only the necessary instances are hydrated. This can be explained because when you use a Func, part of the query is executed client side. It might help to write the code this way to understand what is happening:
When written this way thousands of extra instances are created client side only to be discarded by the Where clause. | |||||||||||||||||||||||||||||||||
| Comment by Juan Antonio [ 02/Mar/16 ] | |||||||||||||||||||||||||||||||||
|
Ok! | |||||||||||||||||||||||||||||||||
| Comment by Craig Wilson [ 02/Mar/16 ] | |||||||||||||||||||||||||||||||||
|
Hi Juan, I believe the problem you are encountering is that, in order to translate your query to MongoDB, we have to be able to see the expression tree. In your second example, you aren't providing us with an expression, but rather a compiled delegate. If you change your argument from Func<T, bool> to Expression<Func<T, bool>>, then it should be translatable. Craig | |||||||||||||||||||||||||||||||||
| Comment by Juan Antonio [ 02/Mar/16 ] | |||||||||||||||||||||||||||||||||
|
Hi Robert, This is working as expected (instance counter is 1):
On the other hand, this code fires the 'multiple hydrate' behaviour. The method receives the same lambda condition as parameter:
Excuse me for not having noticed before. | |||||||||||||||||||||||||||||||||
| Comment by Juan Antonio [ 29/Feb/16 ] | |||||||||||||||||||||||||||||||||
|
Cool, | |||||||||||||||||||||||||||||||||
| Comment by Robert Stam [ 29/Feb/16 ] | |||||||||||||||||||||||||||||||||
|
Oops... I neglected to show the change made to the User class to count how many instances have been created:
| |||||||||||||||||||||||||||||||||
| Comment by Robert Stam [ 29/Feb/16 ] | |||||||||||||||||||||||||||||||||
|
And if I change the queries to not match any users the output is:
Still no sign of any extraneous User instances being created. The 1001 instances reported are the 1001 that were inserted to the collection. The two queries resulted in 0 additional instances being created. | |||||||||||||||||||||||||||||||||
| Comment by Robert Stam [ 29/Feb/16 ] | |||||||||||||||||||||||||||||||||
|
My test database has only those two users (the code drops the collection and then inserts those two users). I've changed the code to insert 1001 documents instead of 2 but the results still look correct. The new code is:
Which produced the following output:
So no extra instances of User are being created. 1001 documents were inserted into the collection and each query (the LINQ version and the Find version) returned 1 document for a total of 1003. | |||||||||||||||||||||||||||||||||
| Comment by Juan Antonio [ 29/Feb/16 ] | |||||||||||||||||||||||||||||||||
|
Hi Robert, Does your test database have those 2 users or more? I reproduce it when are more users and the the query target is not the first element from database (if I filter to an unexisting user I get 0 elements, but all items are hydrated at object constructor). I'll try using ".ToList()" and check again the Linq query. | |||||||||||||||||||||||||||||||||
| Comment by Robert Stam [ 29/Feb/16 ] | |||||||||||||||||||||||||||||||||
|
I am unable to reproduce this. In both cases only one instance of the User class was instantiated. I used the following code, and set a breakpoint on the User constructor to verify when each instance of the User class was created:
|