Why Linq Substring() ignore null value - c#

I just realized that when I request this
Orders.Where(y => y.Sub_Item_Id.Substring(0, 10) != y.Sub_Item_Site_Id.Substring(0, 10))
The query ignore all my null value that may exist in y.Sub_Item_Site_Id. So when I have a value in Sub_Item_Id and null in Sub_Item_Site_Id the query does NOT consider this as !=.
Why?
I also tested the same query with SQL
select
*
from
orders as o
where
LEFT(o.sub_item_id, 10) <> LEFT(o.sub_item_site_id, 10)
And I get the same result. I have all my different value but NOT when I have a value in o.sub_item_id and null in o.sub_item_site_id.
Could you explain how and why SQL and Linq is working like this.

Substring() doesn't ignore null, in your query if one of the strings will be null you will get NullPointerException and if one of the string is shorter than 10 symbols, you will get ArgumentOutOfRangeException:
https://msdn.microsoft.com/library/aka44szs(v=vs.110).aspx
Check your data nad your query.

You may want to add a tag indicating that your LinQ in the background connects to a database to execute SQL there. Without that information, Maksim is correct. In plain Linq-to-Objects C# you would get the appropriate exceptions.
However, as your LinQ is translated and executed as SQL, you just met a surprisingly unintuitive SQL feature: NULL is never equal to anything else. Not even NULL. And NULL is never not equal to anything else. No even a value or another NULL. It just never yields true in a comparison, whatever you compare it to.
You can use the IS syntax to ask if something is NULL. Or you can replace your NULL with a default value before doing your statement. But comparing existing values and NULL will always yield false because NULL is not equal to anything, not even NULL itself.

Relational expressions involving NULL actually yield NULL again. In order to filter null values, you need to use the IS NULL and IS NOT NULL. You can find an answer here.

Related

Checking for nulls in distinct

I have tried a bunch of different ways to do this but every time I try this it throws a null reference exception.
I am trying to filter the values in a field to have a list of the unique values inside that field. It works on fields with no missing values but when i use it on fields that i know to have null values it throws an exception so im assuming that is what i should be filtering for.
The original way i was doing this was just looping through the values and checking if the list of unique values contained the value yet but this was taking a long time and i wanted to harness the power of Linq
List<Graphic> ReturnedGraphics = e.FeatureSet.Features as List<Graphic>;
IEnumerable<string> ValueSet = (
from g in e.FeatureSet.Features
where !uniquevalues.Contains((g.Attributes[_selectedField] == null ? "blank" : g.Attributes[_selectedField].ToString()))
select g.Attributes[_selectedField] == null ? "blank" : g.Attributes[_selectedField].ToString()
) as IEnumerable<string>;
if (ValueSet.Any())
{
uniquevalues.AddRange(ValueSet);
}
I should also add that the reason im adding a range to the list is because there are 5000 values coming in from the server which has a limiter on values to return, however it works for this and shouldn't have an effect on what im trying to do here.
You can't .ToString() null values. Looks like you might be trying to. Candidates for null include lstbxFields.SelectedValue, g.Attributes[someVal]
How about rationalizing your code so that the errors are easier to trap and you're not repeating yourself all over the place?
var selVal = lstbxFields.SelectedValue;
if(selVal == null)
{
//act on this
return; //or throw
}
var selectedValue = selVal.ToString();
var query=
e.FeatureSet.Features
.Select(feature => feature.Attributes[selectedValue])
.Select(attr => attr == null
? "blank"
: attr.ToString())
.Where(attrVal => !uniquevalues.Contains(attrVal));
Your data model is almost certainly "wrong" in the sense that it's very error prone and hard to work with. You should not be converting everything to string but working on the strongly typed objects directly. Doing so will likely fix this bug automatically as it's very likely the NullReferenceException is being thrown when you attempt to ToString a null value.
Not only is it much safer to work on the typed objects, it's also much faster and will result in shorter code.

Adding WHERE to a Simple LINQ Query returns zero results (but shouldn't)

I've got the following query:
var Query = db.ReportCommon
.Where(x => x.ReportType == category)
.Where(x => x.ReportDateTime >= dateStart)
.Where(x => x.ReportDateTime < dateEnd);
category is a variable that I pass in (i.e. 'Short', 'Standard' etc);
dateStart and dateEnd are DateTime values.
This query returns results as expected (approximately 300 odd).
But when I add the following line I get zero results when in reality I should get approximately 2 or 3 less results:
.Where(x => x.PartnerRef.ToUpper() != "TEST");
There are only about 3 entries where the PartnerRef field does contain 'Test' or 'test' or 'TEST' the others are either NULL or contain different Partner Refs (like 'DSW').
Why is this happening and how can I fix it?
Are you sure the values of category, dateStart, and dateEnd are the same?
Also, if you use
.Where(x => x.PartnerRef.ToUpper() == "TEST");
do you get the 2 or 3 records you expect?
You might also want to try running this in LINQPad, which will allow you to experment and see the SQL that EF is generating.
You need to check the SQL generated, but in SQL terms NULL != "TEST" evaluates to UNKNOWN, not TRUE, and so those results wouldn't be returned.
You may be hoping that EF is clever enough to spot this pitfall and emit NULL checks into the SQL, but given everything in your question it may appear that it isn't.
Can't explain why the other PartnerRef values aren't being returned - it all points to some other external factor you haven't identified in the question.
I'm not sure what is happening with your code.
However, if in a certain entry "PartnerRef" is null, than PartnerRef.ToUpper() would throw a null reference exception.
Can it be you are handling that exception somewhere, but result remains empty, because the query was never fulfilled?
LINQ to Databases doesn't need the .ToUpper because sql queries are not case sensitive. You might try profiling the generated SQL to find out why your query is failing. Post your SQL if you still need help.

Why is this if/then statement returning as true?

I have a rather ugly service job that runs through a legacy database and compares it to our production database:
if (vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number) != null) {
var oldDbContractItem = vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).First();
// check to see if there were changes
if (oldDbContractItem.DateStamp != vendorContractItem.Date_Stamp)
{
oldDbContractItem.Update(vendorContractItem);
}
}
I will get an error on var oldDbContratItem, "Sequence contains no elements", yet I just did a != null check. This must be simple, what's going on?
If I could teach people just one thing about LINQ it's this: the value of a query expression is an object that represents the query, not the results of the query. Fundamentally that's your problem; you're treating the query as its results. A query isn't a result any more than a restaurant is a club sandwich. A restaurant is a device which produces club sandwiches; a query is a device that produces results.
This is the test against null you are doing:
vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number) != null
That will always be true; That will always return at least an empty sequence... never a null.
You might be meaning to test that its length is greater than 0?
There's an easier way, though, IMO. Call FirstOrDefault() instead of First() and leave out the pre-test completely. Then instead, test if the result of FirstOrDefault() is null.
var oldDbContractItem = vendorContract.Item
.Where(x => x.ItemNumber == contractItem.Item_Number).FirstOrDefault();
if(oldDbContractItem != null) //would be null if there are no items
{
// check to see if there were changes
if (oldDbContractItem.DateStamp != vendorContractItem.Date_Stamp)
{
oldDbContractItem.Update(vendorContractItem);
}
}
}
Because your query returned a container, it just happened to be empty, the null check is on the return not what the return contains.
try this instead...
if (vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).Any())
{
.....
}
Don't run the query twice. It's inefficient and may introduce a race condition into your code. Also, your logic is much better supported by either using IEnumerator<T> directly, or with a foreach loop.
Use either:
var result = vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).GetEnumerator();
if (result.MoveNext) {
var oldDbContractItem = result.Current;
// ...
}
or
foreach (var oldDbContractItem in vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number)) {
// ...
break;
}
A sequence with no elements is still an object.
Where can return a non-null value, but still resolve to a sequence containing no elements. In your failing statement you are using something else, which is Where().First(). That will be null if the sequence from Where is indeed empty.
There is difference between null and an empty sequence (e.g. something similar to new List<T>()). What you want to do is to use Any() to check whether the sequence contains any elements, or rather replace First() with FirstOrDefault(), which returns null if the sequence contains no element. (If you use that, make sure that null is not a valid value that could be returned by First()).
After using a fix from the accepted answer, you can further debug the LINQ situation (if need be) by using the following steps. LINQ is an exciting technology but takes a while to wraps ones' head around it - a bit of a paradigm shift I would say. Eric's answer hit the nail on the head because he likely helped build the stuff!
Debugging Steps for LINQ
To deal with the issue of no results from the second statement change .First() to .FirstOrDefault() If nothing is found it will return the default value of the data type - if the data type is a class it will return a null value. Your second statement should then work with a null check too and without error.
Then you can debug your LINQ statement to find out why it's doing what it does.
if using LINQ to SQL, Intellisense in Visual Studio 2010 will show you the SQL generated when you hover over a query variable (not the result of a query). If you need the visualizer for VS 2008 it's here
Similarily if you're using LINQ to Entity Framework, you can get the generated SQL using the visualizer plugin here.
I always take the generated SQL from these tools, paste it directly into a query window and run it there. It will show you the empty set you're getting back and if that's a problem you can further debug it in this manner of visualizing the generated statements.

How to short curcit null parameter (SQL)

Hello Friends i have the following query which defeat the very purpose.
A day ago i asked suggestion for to sort circuit the parameter which are null for that i got the suggestion to use
(#firstYrPercent is null OR first_year_percent>=#firstYrPercent) like this to deny null parameter but today when i am running actual query i think that above mentioned idea is of no use.
I am getting sql exception for all those parameter which are null and it is demanding value for those error is this Sql Exception is caught:
"Parameterized Query '(#courseId int,#passoutYear int,#currentBacklog int,#sex int,#eG' expects parameter #currentDegeePercentage, which was not supplied. "
Here is the query please suggest me an alternative:
string cmd = #"SELECT * FROM [tbl_students] WHERE course_id=#courseId
AND branch_id IN(" + branchId + #")
AND (#firstYrPercent is null OR first_year_percent>=#firstYrPercent)
AND (#secondYrpercent is null OR second_year_percent>=#secondYrPercent)
AND (#thirdYrPercent is null OR third_year_percent>=#thirdYrPercent)
AND (#finalYearpercent is null OR final_year_percent>=#finalYearpercent)
AND (#currentDegeePercentage is null OR current_degree_percent>=#currentDegeePercentage)
AND (#passoutYear is null OR passing_year>=#passoutYear)
AND (#currentBacklog is null OR current_backlog<=#currentBacklog)
AND gender=#sex
AND (#eGap is null OR gapin_education<=#eGap)
AND (#highSchoolPercentge is null OR highschool_percentage>=#highSchoolPercentge)
AND (#higherSchoolPercentage is null OR ssc_percentage>=#higherSchoolPercentage)
AND (#grauationPercentage is null OR graduation_percentage>=#grauationPercentage)
AND (#diplomaPercentage is null OR diploma_percentage>=#diplomaPercentage)
AND (#noOfAtkt is null OR number_of_ATKT<=#noOfAtkt)
AND (#date is null OR DOB>=#date)";
You need to make sure you define the #currentDegeePercentage parameter on the Command you are executing - specifically, if you want to pass in that parameter as null, ensure the parameter is added to the command with a value of: DBNull.Value.
If you don't add the parameter to the Command.Parameters collection, or add it but set the value to null (as opposed to DBNull.Value), then you will get the error you are seeing.
The problem is not that the parameter is null but that the parameter is missing. Check for typos (it's "degree", not "degee" [sic]).

Identity Filter Linq .Where

I need to provide a null where clause that has no effect.
Currently I have:
f=>{f!=null;}
However that doesn't really look right. If I were to Select clients, I use
.Select(clients => clients)
With my filter I also get a warning about not all code paths returning a result.
Just return true:
foo.Where(f => true)
Your lambda expression doesn't work for three reasons:
You're trying to use f != null as a statement, which it isn't.
You don't have a return value.
It would reject null values.
The first two can be fixed by removing the braces:
foo.Where(f => f != null)
The last point means it's not really a no-op filter, which is what I guess you meant by "identity filter". Whether it's what you really want or not though, I can't say.

Categories