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.
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.
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.
My vote is for consistency in operator semantics, with the only
special cases being == null and != null.
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-framework-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
>>
>
>