Where statement in a Linq request - c#

I try to execute this Linq request :
var lqClassResult = from classItem in this.dataSet._class.AsEnumerable()
join namespaceItem in this.dataSet._namespace.AsEnumerable()
on classItem.Field<int>("namespace_id") equals namespaceItem.Field<int>("id")
where classItem.Field<string>("class_name").ToLowerInvariant().Contains(className.ToLowerInvariant()) &&
namespaceItem.Field<string("namespace_name").ToLowerInvariant().Contains(namespaceName.ToLowerInvariant())
orderby namespaceItem.Field<string>("namespace_name"),classItem.Field<string>("class_name")
select new {
class_name = classItem.Field<string>("class_name"),
namespace_name = namespaceItem.Field<string>("namespace_name")
};
But when i execute it, Visual Studio Throw a NullReferenceException because of this line :
namespaceItem.Field("namespace_name").ToLowerInvariant().Contains(namespaceName.ToLowerInvariant())
in where clause.
If anyone can help me it would be great

Try
on classItem.Field<int>("namespace_id") equals namespaceItem.Field<int>("id")
let namespaceName = namespaceItem.Field<string("namespace_name")
where classItem.Field<string>("class_name").ToLowerInvariant().Contains(className.ToLowerInvariant()) && namespace != null &&
namespace.ToLowerInvariant().Contains(namespaceName.ToLowerInvariant())

I would guess that namespaceItem.Field("namespace_name") is returning null.
Is this a valid return value for that method? If not, then check your underlying code.
If this is a valid return value then you need to check for a null before calling ToLowerInvariant():
var lqClassResult = from classItem in this.dataSet._class.AsEnumerable()
join namespaceItem in this.dataSet._namespace.AsEnumerable()
on classItem.Field<int>("namespace_id") equals namespaceItem.Field<int>("id")
where classItem.Field<string>("class_name").ToLowerInvariant().Contains(className.ToLowerInvariant()) &&
namespaceItem.Field<string("namespace_name") ! = null &&
namespaceItem.Field<string("namespace_name").ToLowerInvariant().Contains(namespaceName.ToLowerInvariant())
orderby namespaceItem.Field<string>("namespace_name"),classItem.Field<string>("class_name")
select new {
class_name = classItem.Field<string>("class_name"),
namespace_name = namespaceItem.Field<string>("namespace_name")
};
Note the extra null check:
namespaceItem.Field<string("namespace_name") ! = null &&
However, this is only a guess: you need to determine where the null value is coming from.

2 possibilities:
There is no field
Field("namespace_name")
returns null because there is no field-
There isa field, but
Field("namespace_name").ToLowerInvariant().
returns null because the VALUE in namespace_name is a null so ToLowerInvariant also returns null, which will blow the contains.

Related

How to deal with nulls in Linq to SQL with Regex.Replace on Property

The following portion of code is from a larger linq query, but it is the one I need help with:
KnowledgeTypeText = Regex.Replace((from categoryVersion in _Context.ArticleCategoryVersions
join category in _Context.Categories
on categoryVersion.CategoryID equals category.CategoryID
where category.ParentID.HasValue == true
&& category.ParentID.Value == rootKnowledgeTypeID
&& categoryVersion.Version == articleLatestVersions.Version
&& categoryVersion.ArticleID == articleLatestVersions.ArticleID
select category).First().Name, #"(\d+[\\.]?\s*)", ""),
The short version: This part of the query will fetch a category for an article, but it doesn't necessary have to have a value. If it does have a value I need to strip out the numbering at the beginning of the text.
I'm getting exceptions when the category is null because it's obviously trying to do the Replace action on the property Name.
How do I add in code to deal with Nulls? It would be safe to return an empty string, but I'm not sure how to test for it and return an empty string.
If you fail on First() because Sequence contains no elements then replace with .FirstOrDefault().
If you get a value but it is null and then it fails on a null reference when accessing Name then use .FirstOrDefault()?.Name
If it is the Name property that is null then use the ??:
(/* query */).FirstOrDefault()?.Name ?? string.Empty
Read more on:
?. Null-Conditional Operator
?? Operator
In addition it is less readable putting it all inline like this (even more as it seems to be in an object initializer). First have the query and then do the replace:
var result = (from categoryVersion in _Context.ArticleCategoryVersions
join category in _Context.Categories
on categoryVersion.CategoryID equals category.CategoryID
where category.ParentID.HasValue &&
category.ParentID.Value == rootKnowledgeTypeID &&
categoryVersion.Version == articleLatestVersions.Version &&
categoryVersion.ArticleID == articleLatestVersions.ArticleID &&
select category).FirstOrDefault()?.Name ?? string.Empty;
KnowledgeTypeText = Regex.Replace(result, #"(\d+[\\.]?\s*)", "");

Only do Where condition if a value is passed in

I have the following LINQ statement that does on where on the date and a LabID.
I'm passing in a list of LABS and a date, however they are not required, and I could potentially only pass in a date, and no lab, in which case I'd like to get results for all labs for that particular lab.
here is what I have now:
List<dExp> lstDatExp = (from l in ctx.dExp.Include("datLab")
where values.Contains(l.datL.Lab_ID)
&& l.reportingPeriod == reportingPeriod
select l).ToList<dExp>();
But this breaks if the value getting passed in is not there. How do I change this to make sure both of my where statements are optional?
With IQueryable you can simply add conditions in steps:
int? reportingPeriod = ...;
IQueryable<dExp> resultsQuery = // don't use `var` here.
ctx.dExp.Include("datLab");
if (values != null)
resultsQuery = resultsQuery.Where(exp => values.Contains(exp.datL.Lab_ID));
if (reportingPeriod.Hasvalue)
resultsQuery = resultsQuery.Where(exp => exp.reportingPeriod == reportingPeriod.Value);
// additional .Where(), .OrderBy(), .Take(), .Skip() and .Select()
// The SQL query is made and executed on the line below
// inspect the string value in the debugger
List<dExp> results = resultsQuery.ToList();
Here are two ways to do that.
But first, please don't use a single lowercase l as an identifier. It is way too easy to confuse it with the number 1. More generally, stp using abbrevs in yr cde, it mks it hrdr to rd.
First technique:
var query = from lab in ctx.dExp.Include("datLab")
where values == null || values.Contains(lab.datL.Lab_ID)
where reportingPeriod == null || lab.reportingPeriod == reportingPeriod
select lab;
var list = query.ToList<dExp>();
Second technique:
IEnumerable<dExp> query = ctx.dExp.Include("datLab");
if (values != null)
query = query.Where(lab=>values.Contains(lab.datL.Lab_ID));
if (reportingPeriod != null)
query = query.Where(lab=>lab.reportingPeriod == reportingPeriod);
var list = query.ToList<dExp>();
What we do is something like (l.reportingPeriod == reportingPeriod || reportingPeriod == null) So you check to see if the parameter is its default meaning it hasnt been used or if there is something there check it against the database.
You need to check if your values are null before doing the query, and if they are, don't do the extra condition.
List<dExp> lstDatExp =
(from l in ctx.dExp.Include("datLab")
where
(values == null || values.Contains(l.datL.Lab_ID)) &&
(reportingPeriod == null || l.reportingPeriod == reportingPeriod)
select l).ToList<dExp>();
This way if values or reportingPeriod are null they are essentially optional.

Left outer join , Object reference not set to an instance of an object

I am trying to perform left outer join on 2 objects and getting an error : Object reference not set to an instance of an object.
The objects look like that
var deliverables = OCHART.GetACAPValues(organization, ReportingPeriod, FiscalYear, "(09-10.10a) Outreach Significant").ToList();
var references = (from rf in OCHART.References where rf.RefType.Equals("09-10.10a") && rf.Comments.Equals("2") select rf).ToList();
In which deliverables might often return 0 records. Unfortunately I cannot just go and join two tables from database so deliverables must be an object.
Can somebody please point me in the right direction
Thanks,
My code is
var items = (from rf in references
join pt in deliverables on rf.Description equals pt.b into prt
from x in prt.Where(prt2 => prt2.a.Equals(audience)).DefaultIfEmpty()
where rf.RefType.Equals("09-10.10a") && rf.Comments.Equals("2")
select new
{
audience = (string)(audience == null ? "" : audience),
RefType = (string)(rf.RefType == null ? "" : rf.RefType),
RefOrder = (int)(rf.RefOrder == null ? 0 : rf.RefOrder),
refName = (string)(rf.Description == null ? "" : rf.Description),
collumn_attr = (string)(x.b == null ? string.Empty : x.b),
value = (int)(x.ACAP == null ? (int?)null : x.ACAP)
})
.OrderBy(o => o.RefOrder)
.Take(9)
.ToList();
EDIT:
After some more debuging it appears that I get error on following lines in my code
collumn_attr = (string)(x.b == null ? string.Empty : x.b),
value = (int)(x.ACAP == null ? (int?)null : x.ACAP)
I noticed even when I have values (added for testing) in deliverables and when values are matching the query will execute properly, but when there is no match in deliverable that's when I get the error message.
The issue is probably with handling the null values.
I think x is null and is causing a NullReferenceException in the following lines:
collumn_attr = (string)(x.b == null ? string.Empty : x.b),
value = (int)(x.ACAP == null ? (int?)null : x.ACAP)
This judgment is based on the from x in line's DefaultIfEmpty() call, typical of left-outer-joins.
In database code, you would write something like x.ACAP == null to detect the case where there was no matching join element. If you change this replace the 'x.property == null' checks with "x == null" checks, I suspect your problem will clear up.
There's still the problem with the second line - you're going to get an exception at run-time if you try to cast the value (int?)null to an integer. Using a meaningful default int value such as 0 in the case that x == null will clear that up.
If you step through your code, before the query is executed do you actually see "deliverables" and "references" being populated with data ?
Investigate all child tables/properties you're using in your query. The reason you're getting that error is most likely because one of the properties you're using while comparing is null.
.RefType .Comment for example.
Maybe .RefType is null and it's having problems sorting at the end. Difficult to say without seeing what's in those two collections.
Added after your comment:
Note that it's better not to use .Equals() when your variable could be null. Use == instead. Reference: http://www.dotnetperls.com/string-equals
Also imagine that (x.ACAP == null ? (int?)null : x.ACAP) returns a null.
You're casting that whole thing as an int : value = (int)(x.ACAP == null ? (int?)null : x.ACAP). Casting null as n int will obviously fail
Just for the record, the new Null-conditional operators in C# 6.0 could be used like this:
collumn_attr = x?.b ?? string.Empty,
value = x?.ACAP

Linq and anonymous type

select new
{
Selected = (cvf != null && cvf.Deleted==false)
}
The above statement proceeds to check cvf.Deleted even if cvf is null. Then it throws an invalid object reference error.
How do I fix this?
Probably something else going on since && will short-circuit evaluate. That said, try this instead:
select new
{
Selected = cvf != null
? !cvf.Deleted
: false
};

StrongTypingException in Linq

Anybody can tell why the ToList() throws an exception?
var duplicates =
from typeMappings in _liveTable.Where(r =>
(r.ProviderId == providerId) && (r.ExchangeId == exchangeId))
join dataDictionary in _liveDataSet.DataDictionary.Where(r =>
(r.DataDictionaryTypeId == dataDictionaryTypeId))
on typeMappings.DataDictionaryId equals dataDictionary.DataDictionaryId
select typeMappings.ConfigId;
if (duplicates.ToList().Count > 0)
{ ... }
The Exception message is:
'duplicates.ToList()' threw an exception of type 'System.Data.StrongTypingException' System.Collections.Generic.List {System.Data.StrongTypingException}
Thanks
From MSDN:
StrongTypingException
The exception that is thrown by a strongly typed DataSet when the user accesses a DBNull value.
So the problem occurs because one of the properties you access in the query is null. Check which properties of your DataTable are allowed to be null, and check it with a call to IsNull before you try to get the value.
Try to use that to eleminate Null value
var duplicates =
from typeMappings in _liveTable.Where(r =>
(r.ProviderId == providerId) && (r.ExchangeId == exchangeId))
join dataDictionary in _liveDataSet.DataDictionary.Where(r =>
(r.DataDictionaryTypeId == dataDictionaryTypeId))
on typeMappings.DataDictionaryId equals dataDictionary.DataDictionaryId
select new
{ ConfigId = typeMappings.ConfigId = null ? "anyValueyouwhant" : typeMappings.ConfigId};
juste to test without null value

Categories

Resources