Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failed to perform client-side evaluation of expression tree node when filtering based on the presence of values in an array (List<T> Property) #196

Closed
sceee opened this issue Apr 12, 2015 · 12 comments

Comments

@sceee
Copy link

sceee commented Apr 12, 2015

First of all, thank you for developing the library.
I am having an issue creating a query that selects an entry based on the presence of values in an property of that entry.
What I'm basically trying to do is
"Example: Filter based on the presence of a value in an array." at http://rethinkdb.com/api/javascript/filter/

My POCOs are defined as:

[DataContract]
public class IdentityUser
{
...
    [DataMember(Name = "Logins")]
    public List<UserLoginInfoWrapper> LoginsWrapper { get; set; }
...
}

[DataContract]
public class UserLoginInfoWrapper
{
...
    [DataMember]
    public string LoginProvider { get; set; }

    [DataMember]
    public string ProviderKey { get; set; }
...
}

The query I am trying to create is:

Connection.Run(TableUsers.Filter(u => u.LoginsWrapper.Any(l => l.LoginProvider == login.LoginProvider && l.ProviderKey == login.ProviderKey)))

where Connection is an IConnection and TableUsers is an ITableQuery.

The error/exception that is occuring is "Failed to perform client-side evaluation of expression tree node; often this is caused by refering to a server-side variable in a node that is only supported w/ client-side evaluation" based on the InvalidOperationException in private Term AttemptClientSideConversion(IDatumConverterFactory datumConverterFactory, Expression expr) in BaseExpression.cs.

Is this an issue or are such queries not supported at all? Or is my query (lambda expression) simply not written correctly?

mfenniak added a commit that referenced this issue Apr 12, 2015
@mfenniak
Copy link
Owner

Hi @sceee. I've just committed a fix for this issue, adding support for using the Any method to find whether an array contains an element matching a predicate. Please give it a try and see if that addresses your problem. :-)

@sceee
Copy link
Author

sceee commented Apr 12, 2015

Hi @mfenniak ,
Thank you so much for this blazing fast answer and fix. This does indeed fix my issue :)
I didn't expect rethinkdb-net cannot (yet) handle the Any method and didn't even think about this because of the error message.
But thanks again for clarification - this issue should be resolved.

@sceee sceee closed this as completed Apr 12, 2015
@mfenniak
Copy link
Owner

You're welcome, glad that worked.

It would be handy if that error message clarified exactly what was occurring... it is saying that the library doesn't know how to convert an expression into server-side logic, so it is going to try to evaluate it client-side, but then it discovered that there was a binding to a server-side variable in the expression. If it perhaps clarified what part of the expression was trying to run client-side, it might be a bit clearer as to what the problem is.

@sceee
Copy link
Author

sceee commented Apr 12, 2015

Yes that would have might help to understand what the problem is. Of course I am new to using rethinkdb-net so I am also not yet good at "classifying" the error messages ;)

@sceee
Copy link
Author

sceee commented Apr 12, 2015

Sorry, I have to reopen this because I think I experienced a similar issue when using contains.
My query looks like:

Table<..>("..").Filter(w => workspaceIDsWithPermission.Contains(w.ID))

This results in the same error.
Is Contains not implemented? Then I could have a look at your Any code and possibly make a pull request.

@sceee sceee reopened this Apr 12, 2015
@mfenniak
Copy link
Owner

Yeah, looks like Contains is also not implemented. As a workaround, you could use Any. :-) Contains should be simpler than Any to implement, though, because you don't need to convert a predicate into a new expression tree. So similar to the earlier commit, a change in LinqExpressionConverters.cs, but the last half of the code in ConvertEnumerableAnyToTerm isn't required; just call recursiveMap on ...Arguments[1] instead.

@mfenniak
Copy link
Owner

Added support for Enumerable.Contains as well. This should cover your second use-case. Let me know what else you run into; I love having a new rethinkdb-net user reporting the real-life issues they come across. :-) Can't guarantee I can always find the time to fix the issues quickly, but it's great to know about them.

@sceee
Copy link
Author

sceee commented Apr 13, 2015

Thank you very much for the fix again - you were faster than me ;)
But unfortunately, this fix did not resolve my issue, I am getting an InvalidOperationException stating:
"InvalidOperationExpression variable 'w' referenced from scope '', but it is not defined"
Stack:

   System.Linq.Expressions.Compiler.VariableBinder.Reference(ParameterExpression node, VariableStorageKind storage) +6147040
   System.Linq.Expressions.Compiler.VariableBinder.VisitParameter(ParameterExpression node) +73
   System.Linq.Expressions.ExpressionVisitor.VisitMember(MemberExpression node) +24
   System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes) +118
   System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node) +61
   System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes) +138
   System.Linq.Expressions.Compiler.VariableBinder.VisitLambda(Expression`1 node) +356
   System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator) +145
   RethinkDb.Expressions.BaseExpression.AttemptClientSideConversion(IDatumConverterFactory datumConverterFactory, Expression expr) in o:\Daten\Entwicklung\Libraries\rethinkdb-net\rethinkdb-net\Expressions\BaseExpression.cs:200

I assume the problem is that in my query I used the contains method on a (client side generic list) and that cannot be translated into a server-side variable/query.
Let's again see my example (just a bit differently named)

Table<..>("..").Filter(w => SomeGenericList.Contains(w.ID))

Variable w in lambda expression is ok, it's by the DTO type.
SomeGenericList is a List (that means: client-side. I assume it does also not work with any other List so the type may not play a role here).
So I am trying to define a query that selects all entries that do fulfil the expression:

w.ID is in SomeGenericList

In ReQL, I think this could be written as something like:

r.db('myDB').table('Table').filter(r.row('id').eq('SomeID').or(r.row('id').eq('AnotherID')))

Sorry, I did not clearly state this in my latest comment.
Maybe I should open a second issue for this because it's another issue?
I am pleased if I can help making rethinkdb-net better :)

@mfenniak
Copy link
Owner

Hm... what specifically is the type of your SomeGenericList / workspaceIDsWithPermission variable?

I'm just writing a unit test to explore this. It seems like it works fine right now if the variable is an array (eg. int[]). For a List<T> or IList<T>, my current fix doesn't work because the expression is calling a different method than I bound to; I can fix that easily, and will in a few minutes.

For an IEnumerable<T>, it fails to be converted into a server-side type because we don't have a converter for IEnumerable<T>; this is a bit trickier, could probably support this type, but the library would need to make an arbitrary decision on what concrete class to instantiate when converted from the server-side sequence to the client-side type. Or, I suppose, only support a one-way binding.

@sceee
Copy link
Author

sceee commented Apr 13, 2015

Ok. In my case it's a

List<Guid>

(but I may also be using

List<string> or List<int>

at other locations).

@mfenniak
Copy link
Owner

OK, commit 1969700 should fix it for a generic List.

@sceee
Copy link
Author

sceee commented Apr 13, 2015

Thanks again for your fast fix :) It works now as expected.
I will close this issue now again - if I run into another issue I will create a new issue to keep it clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants