C# LINQ object reference not set - c#

Considering the following code
IEnumerable<String> query = null;
query = from x in xml.Descendants(xmlMasterContainerName).Descendants(xmlElementName)
let guid = x.Attribute("guid") ?? new XAttribute("guid", "-1")
where x.Attribute(xmlAttributeIdName).Value == xmlAttributeIdValue
select guid.Value;
I get the 'object reference not set' when trying query.ToList()
This is very probably caused by 'select guid.Value' when 'x.Attribute(xmlAttributeIdName).Value == xmlAttributeIdValue' does not exist.
How can I check the where statement for existing value before selecting?
Thanks

In XLinq, you usually don't use Attribute().Value directly, because of the exact error you are getting. Instead, you cast it. The cast will result in null if Attribute() returned null, so there will be no exception.
So, you would change your where clause to this:
where ((string)x.Attribute(xmlAttributeIdName)) == xmlAttributeIdValue
and your select to this:
select (string)guid
BTW: I would write that code like this:
var query = xml.Descendants(xmlMasterContainerName)
.Descendants(xmlElementName)
.Where(x => ((string)x.Attribute(xmlAttributeIdName)) ==
xmlAttributeIdValue)
.Select(x => (string)x.Attribute("guid") ?? "-1");

If there is no attribute xmlAttributeIdName you will get an exception accessing Value property. Use casting instead (it will return default value). Also you don't need to create attribute - you can simply return value:
IEnumerable<String> query = null;
query = from x in xml.Descendants(xmlMasterContainerName)
.Descendants(xmlElementName)
where (string)x.Attribute(xmlAttributeIdName) == xmlAttributeIdValue
select (string)x.Attribute("guid") ?? "-1";

Related

Avoid NullReferenceException in LINQ Expression on Datatable column

I am stuck with null values in my Datatable "articles". Using LINQ to get a list of articles works for column ArticleId but with column "ArticleVariations" the null values are killing me.
var result = this.articles.AsEnumerable().Where(r =>r.Field<String>("ArticleId").Equals(artNo)); // works. no nulls there ;)
var result = this.articles.AsEnumerable().Where(r =>r.Field<String>("ArticleVariations").Equals(artNo)); // stuck with nulls here
If the column contains nulls, I get an NullReferenceException, Can I avoid this somehow and is it possible to merge both expressions?
You can use null-conditional and null-coalescing operators:
var result = this.articles.AsEnumerable()
.Where(r =>r.Field<String>("ArticleVariations")?.Equals(artNo) ?? false);
The problem obviously occurs because r.Field<String>("ArticleVariations") retuns null. Thus you have to check for null before calling Equals on it.
For that you can call multiple statements within a LINQ-expression:
var result = this.articles.AsEnumerable().Where(r => {
var res = r.Field<String>("ArticleVariations");
if (res != null) return res.Equals(artNo);
else return false;
});
If the field can be null then just reverse your test:
var result = this.articles.AsEnumerable().Where(r => artNo.Equals(r.Field<String>("ArticleVariations")));
Then all you need to do is check that artNo is not null before making the call:
List<Type> result;
if (string.IsNullOrWhiteSpace(artNo))
{
result = new List<Type>();
}
else
{
result = this.articles.... as before
}
Where just takes a function which returns a bool to determine if it should filter an item out of a collection. You can write it with a multi-statement body just like any other function to make nulls easier to deal with. Something like this should be a good starting point:
.Where(r => {
string articleVariations = r.Field<string>("ArticleVariations");
return articleVariations != null && articleVariations.Equals(artNo);
});
IF you want to combine those checks somehow to build a list where one or the other of the given fields matches your artNo, you can just add it to the function body.
If the column contains nulls, I get an NullReferenceException, Can I avoid this somehow
Avoid using instance Equals methods where possible. Use the respective operators or static Equals methods because they handle correctly nulls for you.
In your concrete case, the easiest way is to replace Equals with ==:
var result = this.articles.AsEnumerable()
.Where(r => r.Field<string>("ArticleId") == artNo);
var result = this.articles.AsEnumerable()
.Where(r => r.Field<string>("ArticleVariations") == artNo);
and is it possible to merge both expressions?
It depends on what do you mean by "merging" them. If you mean matching article or variation by the passed artNo, then you can use something like this
var result = this.articles.AsEnumerable()
.Where(r => r.Field<string>("ArticleId") == artNo
|| r => r.Field<string>("ArticleVariations") == artNo);

LINQ C# Join with Left-Join result

I'm trying to do a left-join with the result of another left-join but in some cases it returns me null reference error (obviously), is there any way to do this without using foreach after select?
var result = from f in foo
from ex in exp.Where(w => w.id == f.idFoo).DefaultIfEmpty()
from te in tes.Where(w => w.id == ex.anyID).DefaultIfEmpty()
select new
{
var1 = f.something,
...
var2 = te.anything
};
That's happening because DefaultIfEmpty is returning a sequence with a single null element. Then you are trying to access properties on a null element.
Use the overload of DefaultIfEmpty to return a non-null default value (of the appropriate data type):
var result = from f in foo
from ex in exp.Where(w => w.id == f.idFoo)
.DefaultIfEmpty(new Exp())
from te in tes.Where(w => w.id == ex.anyID)
.DefaultIfEmpty(new Tes())
select new
{
var1 = f.something,
...
var2 = te.anything
};
That way you won't be trying to access properties on null elements.
Edit based on comments. In the query, one place that null elements arise is when a Where results in zero matches. For instance, in the third from the ex variable might be a sequence of one null element, and again in the select the te might also be such a sequence. In both cases, accessing a property will throw an exception.
Alternatively, you could do a null test every time you are going to access a property. That would become verbose fast.
Something like this:
var2 = te != null ? te.anything : null

Comparing a nullable column throws "Unable to cast the type..." exception

My entity NewsItem has a nullable foreign key property: LibraryID of type int?.
My issue is when I query the property and compare it with any value except null, I get exceptions.
Initially my code was:
int? lid = ...
var results = context.NewsItems
.Where(n => n.LibraryID == lid);
but it gives me no results at all, no matter what lid is.
So, I tried:
var results = context.NewsItems
.Where(n => n.LibraryID.Equals(lid));
gives exception:
Unable to create a constant value of type 'System.Object'. Only primitive types or enumeration types are supported in this context.
and then I tried:
var results = context.NewsItems
.Where(n => lid.Equals(n.LibraryID));
and got:
Unable to cast the type 'System.Nullable`1' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.
and this:
var results = context.NewsItems
.Where(n => object.Equals(lid, n.LibraryID));
gives same exception as the last one.
Now I was desperate, so I tried to complicate stuff (like other forums suggested, for example here):
var results = context.NewsItems
.Where(n => (lid == null ? n.LibraryID == null : n.LibraryID == lid));
but still getting same exception.
So... any SIMPLE workarounds?
How about
var results = context.NewsItems
.Where(n => lid.HasValue ? lid.Value == n.LibraryId.Value : (!n.LibraryId.HasValue) );
Hmm, that first snippet should work. I've used nullables like that many times. First thing I'd do is a sanity check just to make sure LibraryID is really int? and not long? or similar.
Other than that, you can try this:
var results = context.NewsItems
.Where(n => (lid.HasValue ? n.LibraryID == lid.Value : !n.LibraryID.HasValue));
Or to avoid the ?: within the query:
var results = lid.HasValue
? context.NewsItems.Where(n => n.LibraryID == lid.Value)
: context.NewsItems.Where(n => !n.LibraryID.HasValue);
It seems that EF does not find the correct operator overload. Therefore it produces wrong results if you set lid = null.
Use linq to objects by adding AsEnumerable() to your query and everything is fine:
var results = context.NewsItems.AsEnumeryble().Where(n => n.LibraryID == lid);
According to the MSDN docs (which I finally found), .Where() will only filter your collection. If you want to see if there are actually results, resolve by lazily executing the filtered query with .ToList(), GetEnumerator, or enumerating the collection with foreach;
This method is implemented by using deferred execution. The immediate
return value is an object that stores all the information that is
required to perform the action. The query represented by this method
is not executed until the object is enumerated either by calling its
GetEnumerator method directly or by using foreach in Visual C# or For
Each in Visual Basic.
http://msdn.microsoft.com/en-us/library/bb534803.aspx
int? lid = ...
var results = context.NewsItems
.Where(n => n.LibraryID == lid).ToList();
var results = context.NewsItems
.Where(n => n.LibraryID.HasValue && n.LibraryID.Value == lid.Value );
edit:
Previous filter was based on my understanding that you wanted to filter to entires having a particular value. Updated will filter to null or value.
var results = context.NewsItems
.Where(n => !n.LibraryID.HasValue || n.LibraryID.Value == lid.Value );

linq where clause causes exception

var nextItem = ql.Fragments.Where(x => x.AddedToFinal.Equals(false));
x.AddedToFinal is bool and ql.Fragments is not null
this linq statement sporadically get this exception:
System.NullReferenceException: Object reference not set to an instance
of an object.
at System.Linq.Enumerable.WhereListIterator1.MoveNext() at
System.Linq.Enumerable.Count[TSource](IEnumerable1 source)
There is a question already that should have answered this( linq where clause and count result in null exception) but this is impossible since the field is a not null Boolean, and this isn't a database object it is a list
Just added:
The code where I populate the list is multi-threaded. different fragments add items to the list after they have retrieved the items from the db:
.....
xe = XElement.Parse(result);
XmlFragment xf = new XmlFragment();
xf.Fragment = xe;
xf.LetterQueueOID = lq.LetterQueueOID;
xf.ParentGroupNodeName = ParentGroupNodeName;
xf.LinkingField = GroupNode.LinkingField;
xf.GroupNodeName = GroupNode.GroupNodeName;
lock (queuedLetters[lqOID])
{
if (lq.Fragments == null)
lq.Fragments = new List<XmlFragment>();
lq.Fragments.Add(xf);
}
ql.Fragments itself isn't null, but one of the elements in the enumeration is null. I'm guessing that is a problem in and of itself, but you could modify the statement to be:
var nextItem = ql.Fragments.Where(x => x != null &&
x.AddedToFinal.Equals(false));
Although that doesn't solve the problem of why one of the elements in the collection was null to begin with.
x.AddedToFinal is bool and ql.Fragments is not null this linq statement sporadically get this exception:
Then one of the elements of ql.Fragments is null so that
x.AddedToFinal
is throwing a NullReferenceException for some value of x in ql.Fragments. You could say
var nextItem = ql.Fragments
.Where(x => x != null)
.Where(x => !x.AddedToFinal);
but you should probably find out why there are null elements in your collection.
I would check if x is null
var nextItem = ql.Fragments.Where(x => x != null && x.AddedToFinal.Equals(false));
Are you sure all rows have a value for AddedToFinal ?!!
System.NullReferenceException: Object reference not set to an instance of an object.
at System.Linq.Enumerable.WhereListIterator1.MoveNext() at System.Linq.Enumerable.Count[TSource](IEnumerable1 source)
As you can see in exception Iterator can't move or read next row.
Be sure all rows have a value for this field.

Where Predicates in LINQ

How can I specify conditions in Where predicates in LINQ without getting null reference exceptions. For instance, if q is an IQueryable how can I do like:
Expression<Func<ProductEntity,bool>> predicate = p => !search.CategoryId.HasValue || (search.CategoryId.HasValue && search.CategoryId == p.CategoryId);
var q2 = q.Where(predicate);
Here search is an object that holds possible search conditions that may or may not be set like search.CategoryId might not be set but if it is I want to get the products that are set by that condition.
When I do this I get null reference exceptions.
You can use the null-coalescing operator ?? to replace a possible null value with a default value. The following sets tries to match the search.Category if it exists or simply creates an "always true" expression. This will be optimized by any good Linq query provider (e.g. LinqToSql).
Expression<Func<ProductEntity,bool>> predicate = p => (search.CategoryId ?? p.CategoryId) == p.CategoryId);
var q2 = q.Where(predicate);
Another possibility would be to dynamically compose a query predicate using PredicateBuilder. That's the way I do it for searches with a similar pattern as you use:
var predicate = PredicateBuilder.True<Order>();
if (search.OrderId))
{
predicate = predicate.And(a => SqlMethods.Like(a.OrderID, search.OderID);
}
// ...
var results = q.Where(predicate);
Let's dissect the line:
Expression<Func<ProductEntity,bool> predicate = p => !search.CategoryId.HasValue
|| (search.CategoryId.HasValue && search.CategoryId == p.CategoryId)
var q2 = q.Where(predicate);
So how many ways can we get null problems?
search (your "captured" variable) could be null
p could be null, meaning there is a null in the list
you've handled the case of search.CategoryId being null (Nullable<T>)
but maybe p.CategoryId (the category on a record in the list) is null (Nullable<T>) - however, I'm not sure that this would cause a NullReferenceException
q (the list / source) could be null
So: out of 5 options you've eliminated 1; look at the other 4? There is also the definite possibility that the issue is caused by something invisible not shown in the code; for example the get could be:
public int? CategoryId {
get {return innerObject.CategoryId;}
}
and innerObject could be null; if you eliminate the other 4 (pretty easy to do), look at at this one as a last resort.

Categories

Resources