Question

I'm trying to create a not in clause with the NHibernate Criteria API using NHLambdaExtensions. Reading the documentation I was able to implement the in clause by doing

.Add(SqlExpression.In<Zone>(z => zoneAlias.ZoneId, new int[] { 1008, 1010 }))

However, when I wrap it around SqlExpression.Not I get the error

Error   5   The best overloaded method match for 'NHibernate.LambdaExtensions.SqlExpression.Not<oms_dal.Models.Zone>(System.Linq.Expressions.Expression<System.Func<oms_dal.Models.Zone,bool>>)' has some invalid arguments
Error   6   Argument '1': cannot convert from 'NHibernate.Criterion.ICriterion' to 'System.Linq.Expressions.Expression<System.Func<oms_dal.Models.Zone,bool>>'

I'm using this piece of code

.Add(SqlExpression.Not<Zone>(SqlExpression.In<Zone>(x => zoneAlias.ZoneId, new int[] { 1008, 1010 })))

How can I accomplish this? Using the regular Criteria API I was able to do this

.Add(Restrictions.Not(Restrictions.In("z.ZoneId", new[] { 1008, 1010 })))
Was it helpful?

Solution

Haven't worked with criterion directly (I generally use Linq2NH), but it looks like Not simply wants a boolean lambda, so you can't give it another criterion. This may work, though I've seen NH have trouble with array members in lambdas:

.Add(SqlExpression.Not<Zone>(z=>new[]{1008,1010}.Contains(z.ZoneId))

EDIT: crap. What's going on here is that the framework is not actually using the lambda, so while this compiles, the framework never actually calls it in the process of running the query. It is instead reflectively examining the MSIL of your delegate, reverse-engineering your lambda expression and converting that to a string for the SQL command. That is, obviously, a rather complex process that the designers try to simplify by having you specify hints about what you're doing (in this case the type of SqlExpression you declared) and looking for patterns to identify the process. In this case, though, even given the hints, the framework has no clue what you're trying to do.

If the translator behind evaluating Not() clauses cannot divine the purpose of logic loops or method calls, you may well be stuck with

.Add(SqlExpression.Not<Zone>(z=>z.ZoneId == 1008
                                || z.ZoneId == 1010))

Goodness knows I've had to boil down expressions this way for Linq2NHibernate to work correctly.

OTHER TIPS

Using the old world with the lambdas seems to work:

.Add(Expression.Not(SqlExpression.In<Zone>(z => zoneAlias.ZoneId, new int[] { 1008, 1010 }));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top