1

I've been looking through some MS reference material for an upcoming exam and have found a supposedly previous question where I disagree with the answer.

Upon consideration, I'm going to post a screenshot of the question rather than condense the problem just in case I abstract out any pertinent information to the question at hand.

enter image description here

The issue I have is that they give the answer as B whereas I think it should be A for the following reasons.

The where clause in the LINQ query has two criteria it has to compare against one where the Years match in the DateTime? object and the method parameter.

However, I'm more interested in why they think a null check is necessary due to the parameter type being a non-nullable int. Unassignment and attempting to assign null prior to passing the parameter by value will result in a compiler error.

If the year param can never be null, there will never be a null DateTime match - rendering the null check superfluous.

I can see why B would also yield expected results, but is there anything wrong with answering A.

(P.s. I've read - Comparing non nullable `int` to `null` (LINQ) which seems to back up my theory, I'm just squeamish about disagreeing with reference material)

Ahsan Ali
  • 124
  • 8
James
  • 356
  • 2
  • 13
  • @sam a fair comment - I was dithering about whether to include the image in the first place but I wanted to keep it in a readable format as well as not have to create the supporting code around it. I think the intent by the creators of this question is to consider the principles rather than consider how you would get this into a compilable state. – James Jan 15 '20 at 14:13
  • The SQL Server can have null for a DateTime while c# DataTime is not nullable. – jdweng Jan 15 '20 at 14:24
  • you should ask the query's author ... answer `A` AFAIK should work if you take in the account that it's EF (as expression will be translated to SQL)... but it would not in "plain C#" (as other wrote would throw an exception) – Selvin Jan 15 '20 at 14:24
  • fx A can be translated direcctly to `WHERE DATEPART(year, OrderDate) = @year` ... and B to `WHERE OrderDate IS NOT NULL AND DATEPART(year, OrderDate) = @year` ... from the SQL point of view they will return the same results – Selvin Jan 15 '20 at 14:28

2 Answers2

1

Suppose you choose A , if the Date is null you will get the following Exception

Nullable object must have a value.
  + System.ThrowHelper.ThrowInvalidOperationException(System.ExceptionResource)
  + Nullable<T>.get_Value()

for example

DateTime? dt = null;
 if (dt.Value.Year == 2010) Console.WriteLine("Accepted Value");

Give Error

Ibrahem Uwk
  • 137
  • 9
  • but there is no such code in the question ... `dt.Value.Year` is translated directly to SQL code – Selvin Jan 15 '20 at 14:08
0

The application must meet the following requirements:

  • Return only orders that have an OrderDate value other than null.
  • Return only orders that were placed in the year specified in the year parameter

Also, line 1 seems to be showing you the definition of OrderDate

public DateTime? OrderDate;

The question is telling you that the OrderDate is a nullable DateTime object, and that you need to check that it has a value.

Edit: I did try this for myself using SQLEXPRESS and LINQPad 5, and I see now that answer A does work in the context of LINQ to SQL because it gets converted to

WHERE DATEPART(Year,OrderDate) = @year

And this will filter out null OrderDates.

All I can say, then, is why I believe answer B is the "preferred" answer.

Answer A in all other C# contexts will throw an InvalidOperationException "Nullable object must have a value", and it just happens to work in this context because it is LINQ to SQL.

Answer B will work both in a C# context and in a LINQ to SQL context, so of the two possible answers, it is the safest, and will help prevent you from using an answer like A in a context where it would fail. Also, I believe that it communicates more clearly and explicitly that you want to filter out null order dates. There may be a minor performance hit doing the additional null check, but unless there is a measurable performance problem, then readability is more important than minor performance improvements. If I did use answer A, I would include plenty of comments describing the LINQ to SQL behavior explaining why the null check is not necessary.

Community
  • 1
  • 1
TJ Rockefeller
  • 3,178
  • 17
  • 43
  • I appreciate that - but due to the second part of the Where clause, there won't ever be a match if the DateTime is null. In that situation you'd compare a null DateTime year value to a value *that can never be null*, the condition is not met and so the null DateTime is not included in the return. – James Jan 15 '20 at 14:08
  • but the code is not executed on C# side ... it is translated directly to SQL fx to `WHERE DATEPART(y, OrderDate) = @year` ... with this SQL code checking if it's null is not necessary as `int is not equal NULL` in SQL (but also is not not equal, hehe so `int !=NULL` is false) – Selvin Jan 15 '20 at 14:09
  • @James If you don't believe the answer, then my only suggestion is just go try it. I can't say that I'm very experienced with LINQ to SQL, but in normal C# contexts you will get a runtime exception if you call `order.OrderDate.Value.Year` when OrderDate is null. – TJ Rockefeller Jan 15 '20 at 14:18
  • @TJRockefeller I suspect you and Ibrahem are telling me the same thing. It very much seems like I've fallen into the trap of equating no value (i.e. unassigned) and a value of null. I'm looking into the default unassigned value of DateTime? to see if I can confirm this. – James Jan 15 '20 at 14:22
  • @TJRockefeller I've looked into HasValue and it's pretty much a null check for the underlying type. The legitimacy of leaving OrderDate undefined is unlikely to be within the scope of the question given the answers available and Selvin's comments. – James Jan 15 '20 at 14:46