> 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)
they indeed spend a lot of time on this.
> 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.
odd. 'Equals' method handling is simply doing a
Expression.Equal(HandleExpression(arg1), HandleExpression(arg2));, which
will result in a binary expression similar to '='. Just make sure you're not
testing for op_Equality but the operator instead in the binary expression
handler.
llblgen pro does:
A == B produces A = B
A != B produces A <> B
Equals(A, B) produces A = B
It's really doing what the developer asks you to, not to assume what
the developer THINKS. If the developer says: where c.Foo == d.Foo, that's
really a predicate c.Foo = d.Foo in the SQL query, nothing more, nothing
less. If the developer wants extra null checks, he can add them to the
query, or leave them out.
> 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
This is strange, because the variable passed is really a
constantexpresson in the expression tree, so this constant has to be read
before the predicate is created, at least that's IMHO how you should do it.
If you do it that way, you get the same behavior as if you passed a null
constant:
[Test]
public void NullComparsonTests()
{
using(DataAccessAdapter adapter = new DataAccessAdapter())
{
LinqMetaData metaData = new LinqMetaData(adapter);
var q = from o in metaData.Order
where o.ShippedDate == null
select o;
var count = 0;
foreach(var v in q)
{
count++;
}
Assert.AreEqual(19, count);
DateTime? nullValue = null;
var q2 = from o in metaData.Order
where o.ShippedDate == nullValue
select o;
count = 0;
foreach(var v in q)
{
count++;
}
Assert.AreEqual(19, count);
}
}
works, give exactly the same query, with an IS NULL predicate. I think NH
should do that too, it is what the developer asked for. (I count in a loop
btw, to prevent the appending of the scalar count to the query for testing)
> 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.
coalesce is really for projections or advanced predicates in join's
ON clauses but most of the time, you don't need it, as NULL values are not a
problem inside SQL, they are outside the DB.
> 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.
huh? Linq to Sql don't follow the behavior of SQL, they follow the
behavior of C# and VB.NET. If you want to follow SQL, you simply should do
what you logically think: convert the predicate to what it says: comparison,
no extra goo around it.
> 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.
B is actually what Linq to sql does, hence the problems they had in
the connect issue.
FB
> 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
> >