Node.ByIndexLookup and Where clause throwing excep

2019-09-06 16:10发布

问题:

I am trying to understand as to why the neo4jClient throws an exception, hope someone here could help me better understand whats going on.

first of all the following code works!!

            qry = qry.Start(new 
        { 
            city = Node.ByIndexLookup(model.City.IndexName, "Label", data.RegistredAddress.City),
            state = Node.ByIndexLookup(model.State.IndexName, "Label", data.RegistredAddress.State),
            country = Node.ByIndexLookup(model.Country.IndexName, "Label", data.RegistredAddress.Country),
        });
        qry = qry.Match("(city)-[:BELONGS_TO_STATE]->(state)-[:BELONGS_TO_COUNTRY]-(country)").Return<Node<model.City>>("city");

but when I replace it with a different construct as below, it throws an exception

            qry = qry.Start(new 
        { 
            city = Node.ByIndexLookup(model.City.IndexName, "Label", data.RegistredAddress.City),
        });
        qry = qry.Match("(city)-[:BELONGS_TO_STATE]->(state)-[:BELONGS_TO_COUNTRY]-(country)");
        qry = qry.Where<model.State>(state => state.Label == data.RegistredAddress.State);
        qry = qry.AndWhere<model.Country>(country => country.Label == data.RegistredAddress.Country);
        var finalQry = qry.Return<Node<model.City>>("city");

I get an exception at the line where its trying to add a Where clause.

System.NotSupportedException: Unhandled node type MemberAccess in MemberExpression: value

detail of the stack trace is as follows

Neo4jClient.Cypher.CypherWhereExpressionVisitor.VisitMember(MemberExpression node) in c:\TeamCity\buildAgent\work\f1c4cf3efbf1b05e\Neo4jClient\Cypher\CypherWhereExpressionVisitor.cs: line 145 System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor) System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) Neo4jClient.Cypher.CypherWhereExpressionVisitor.VisitBinary(BinaryExpression node) in c:\TeamCity\buildAgent\work\f1c4cf3efbf1b05e\Neo4jClient\Cypher\CypherWhereExpressionVisitor.cs: line 65 System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor) System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression1 node) System.Linq.Expressions.Expression1.Accept(ExpressionVisitor visitor) System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) Neo4jClient.Cypher.CypherWhereExpressionBuilder.BuildText(LambdaExpression expression, Func2 createParameterCallback) in c:\TeamCity\buildAgent\work\f1c4cf3efbf1b05e\Neo4jClient\Cypher\CypherWhereExpressionBuilder.cs: line 15 Neo4jClient.Cypher.CypherFluentQuery.<>c__DisplayClassd.<Where>b__c(QueryWriter w) in c:\TeamCity\buildAgent\work\f1c4cf3efbf1b05e\Neo4jClient\Cypher\CypherFluentQueryWhere.cs: line 11 Neo4jClient.Cypher.CypherFluentQuery.Mutate(Action1 callback) in c:\TeamCity\buildAgent\work\f1c4cf3efbf1b05e\Neo4jClient\Cypher\CypherFluentQuery.cs: line 40 Neo4jClient.Cypher.CypherFluentQuery.Where(LambdaExpression expression) in c:\TeamCity\buildAgent\work\f1c4cf3efbf1b05e\Neo4jClient\Cypher\CypherFluentQueryWhere.cs: line 10 Neo4jClient.Cypher.CypherFluentQuery.Where[T1](Expression1 expression) in c:\TeamCity\buildAgent\work\f1c4cf3efbf1b05e\Neo4jClient\Cypher\CypherFluentQueryWhere.cs: line 34

Just curious to know what is the difference here & which of the 2 approach is a preferred way to query for performance reasons when boath works.

Regards Kiran

回答1:

OK, I have a solution that will get the code working, but to get it to work as you currently have it you'll need to put in a feature request / bug report at the Neo4jClient Issues Page. Issue 151 has been raised.

First, the solution:

You need to take the RegisteredAddress part of your data object and put it into another object, so:

var registeredAddress = data.RegisteredAddress;

then use that in your query:

var qry = qry.Where((model.State state) => state.Label == registeredAddress.State);

This will work and give you the results you want / need.

The reason:

Neo4jClient takes your lambda expression and parses it internally using an ExpressionVisitor based class. This at the moment will only go one deep in terms of looking for 'constant' expressions (i.e. actual values). Because data.RegisteredAddress.State is 2 expressions deep, it can't find the constant expression and such can't use it in the query.

Performance

I don't know for certain, but I would have thought the latter approach was fastest as traversal in neo4j is lightning fast, and you've only done one index lookup. There's probably not a whole lot in it to be honest...



标签: neo4jclient