> I should note there's a sub-decision I forgot to mention... how to handle
a
> variable with known null content.
> 
> int? nullVariable = null;
> int? notNullVariable = 1;
> 
> .Where(x => x.Data == nullVariable)
> .Where(x => x.Data == notNullVariable)
> 
> In EF and LINQ to SQL, these both generate:  Data = @p0, where @p0 is
NULL.
> This maintains consistency with the model of not being able to compare
> against null "things" directly.  The only special case with the null
> behavior is comparing directly with the null literal (== null, != null
> generate IS NULL and IS NOT NULL).
> 
> In NHibernate, it currently generates IS NULL for the first, and = @p0 for
> the second.

        they really aren't different: comparing to a variable is really
comparing to a constant. EF makes a difference for this, as they inline
constants, which is IMHO stupid, but alas, their choice. So if you see a
constant expression: use the value and handle the expression the same as if
there's a constant. This gives the same behavior as with the constant: IS
NULL, which is what is expected if the constant / variable is NULL. 

> Again there are two options for handing the case of Data == nullVariable:
> 
> Option C:  Generate = @p0.  This is consistent with EF and LINQ to SQL.
If
> users want to get the IS NULL behavior, they could use Equals(variable,
> NULL) as discussed earlier.

        bad choice, for reasoning: check the connect issue you pointed to. 

> Option D:  Generate IS NULL.  This is often what might be expected, but it
> is inconsistent with how the equality operator works when the "variable"
is
> a database column for example.

        Yes, but the predicate is also different: comparing to an in-memory
variable or a constant is equal to the query: both will result in a
parameter with the value of the constant / variable. So you can test up
front whether the value is NULL or not, so you can include an IS NULL
predicate. The field comparison is different indeed, but that's what the
developer asked for. If the developer wants an extra null check, he can add
that. It's more clear. 

> My vote is for consistency in operator semantics, with the only special
> cases being == null and != null.

        you won't get that: left join creating null values, used in
aggregates which are used in comparisons -> what to do? Mind you: the linq
query in memory in this case doesn't work with nullable typed scalars. 

                FB

> 
> For this, I vote for C.
> 
>           Patrick Earl
> 
> On Fri, Oct 29, 2010 at 1:29 AM, Richard Brown (gmail)
> <[email protected]> wrote:
> > I think option B has come about because some programmers (misguidedly,
> > IMHO) think they can test their queries in-memory, and expect the
> > generated SQL to behave exactly the same as linq-to-objects.  I'm sure
> > it's been mentioned several times in the users group that the
> > preferred way to test queries is against a 'real' database, which is why
> I'm not a huge fan of option B.
> >
> > In addition, having used the previous NH-contrib linq provider in a
> > largish production system, I noted that a not insignificant amount of
> > time was spent trying various combinations of linq expression, while
> > sitting with either NH-Prof or the log files, to try and figure out
> > how to get the desired SQL to come out the other side.
> >
> > So I think (and I hope I'm not proven wrong in the future), that
> > opaqueness wins ... i.e., that the generated SQL should be as
> > predictable as possible, certainly for simple queries.
> >
> > So +1 for option A.
> >
> >
> > -----Original Message----- From: Patrick Earl
> > Sent: Friday, October 29, 2010 7:20 AM
> > To: [email protected]
> > Subject: Re: [nhibernate-development] Linq Null Operations
> >
> > Okay, here's what happens in the various frameworks currently:
> >
> > Linq to SQL:
> > A == B produces A = B
> > A != B produces A <> B
> > Equals(A,B) produces (A is null and B is null) or (A is not null and B
> > is not null and A = B)
> >
> > Entity Framework:
> > A == B produces A = B
> > A != B produces A <> B
> > Equals(A,B) produces an exception.  There's no easy way to do the long
> > form as far as I can see.
> >
> > NHibernate:
> > A == B produces (A is null and B is null) or (A = B) [which
> > incorrectly produces nulls sometimes] A != B produces (A is null) and
> > (B is not null) or (A is not null) and (B is null) or A<>B [which also
> > incorrectly produces nulls sometimes]
> > Equals(A,B) produces an exception.
> >
> > A == null and A != null generate A is null and A is not null in all
> > frameworks.
> >
> > Now that we know how the systems work, consider the other frames of
> > reference.
> >
> > For .NET developers, they're used to being able to compare nulls
> > directly.  See this connect bug report that also shows many people
> > having issues again and again with this mismatch.  They consider it to
> > be a problem with the linq system.
> >
> > http://connect.microsoft.com/data/feedback/details/607404/entity-frame
> > work-and-linq-to-sql-incorrectly-handling-nullable-variables
> >
> > In SQL however, developers tend to write plain A = B most frequently,
> > sometimes using coalesce or other null checks as needed.  As an
> > example from our code base, the majority of the time we don't need to
> > compare against nulls.
> >
> > So, it's clear there are valid reasons for going either way.  I would
> > propose that it would be best to follow the nature of SQL, copying the
> > behavior of Linq to SQL and the Entity Framework.  Though it will lead
> > to some confusion for users, it won't lead to unexpectedly complicated
> > queries from simple expressions.
> >
> > So, here are the basic options.
> >
> > Option A:  Simple equality.  Follows SQL, Linq to SQL, and EF, but is
> > sometimes confusing.
> > Option B:  C#-style equality with long expression.  Rules are clear
> > but generated SQL is sometimes poor.
> >
> > This choice should be made deliberately.
> >
> > My vote is for A.
> >
> >       Patrick Earl
> >
> > On Thu, Oct 28, 2010 at 9:17 PM, Patrick Earl <[email protected]> wrote:
> >>
> >> Ultimately, I'm fine diverging from the standard way of doing things
> >> to make null equality work as expected from an object programmer's
> >> perspective.  However, in cases where the programmer is sure there
> >> cannot be nulls, it would be great to have some technique to specify
> >> that A = B should be used instead of (A is null and B is null) or (A
> >> is not null and B is not null and A = B)  [ See
> >> http://216.121.112.228/browse/NH-2398 ].  If the decision is to go
> >> the "object emulation route," as is in the code so far, I'd at least
> >> like to allow the expression to be a dialect-specific thing, since
> >> some databases can use IS DISTINCT FROM or <=>.
> >>
> >> Things seem a little slow around the list this week.  Maybe
> >> everyone's in crazy work mode like we've been recently. :)
> >>
> >>       Patrick Earl
> >>
> >
> >

Reply via email to