Not all code paths return a value - c#

I am having this Linq To SQL query which is taking Customer Category from database.The CustCategory will be defined already.Here is the query.
public IList<string> GetAccountType()
{
using (var db = new DataClasses1DataContext())
{
var acctype = db.mem_types.Select(account=>account.CustCategory).Distinct().ToList();
if (acctype != null)
{
return acctype;
}
}
}
Currently I am getting an error that Not all code paths return a value.If I am always certain that the value is there in the database then do I need to check for null,If I need to check for null then how do I handle this.
Can anyone help me with this.
Any suggestions are welcome.

Since Enumerable.ToList never returns null (see the Return Value section of the documentation), you can safely remove the if.
EDIT: Note that, no matter what your database contains, acctype will never be null:
If no value is found in the database, the return value will be an empty list (which is different than null).
If one record is found and its value is null, the return value will be a valid list with one entry, whose value is null. Still, the list itself is not null.

What happens if:
if (acctype != null)
Is null? What is your method supposed to return?
You need to return something

This is not about LINQ to SQL, the method GetAccountType() must return IList<string>. You should return return acctype; and then check this returned list later using Any(), something like:
if(GetAccountType.Any()){
//not empty
}

How about something like this for a fairly clean and readable solution?:
(Note, updated: removed the check for null, since it would clearly not have any effect).
public IList<string> GetAccountType()
{
var acctype = new List<string>();
using (var db = new DataClasses1DataContext())
{
acctype = db.mem_types.Select(
account=>account.CustCategory).Distinct().ToList();
}
return acctype;
}

You need to return a value from your function:
public IList<string> GetAccountType()
{
using (var db = new DataClasses1DataContext())
{
var acctype = db.mem_types.Select(account=>account.CustCategory).Distinct().ToList();
if (acctype != null)
{
return acctype;
}
}
return acctype;
}

Related

foreach looping variable throws NullReferenceException but Enumerable is not null

Some people decided to close my previous question, but the question they linked (What is a NullReferenceException, and how do I fix it?) did not have an answer. This question is fundamentally different since the enumerable is populated. It is not null. Just as the first answer stated, I placed "strategic breakpoints" and checked the variables.
I'm debugging a XUnit test and it turns out that in my business logic the iteration variable in the foreach loop is throws an exception "Object Reference not set to instance of object". However, the list over which the iteration is happening is NOT null. I can see that when I'm debugging. Here is the code:
Business logic:
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray = _utils.GetRegions(someParam); // this is not returning null
}
foreach (var region in regionArray)
{
var query = from dataSet in myDataSets
where dataSet.Location == region
select dataSet;
var queryResult = query.FirstOrDefault();
if (queryResult == null)
{
// do stuff
} else if (queryResult.State != States.Provisioned)
{
// do stuff
}
}
Here is how I am mocking the _utils.GetRegions call, but I dont think thats the problem.
private Mock<IUtils> _mockRegionUtils;
[Fact]
public void ItWorks()
{
// do stuff
_mockRegionUtils = new Mock<IUtils>();
_mockRegionUtils.Setup(utils => utils.GetRegions(It.IsAny<ISomeParam>())).Returns(new List<string>() {"america", "china"});
// call business logic
}
I have checked all the types in the debugger. regionArray.GetType() returns {System.Collections.Generic.List`1[System.String]}. when I type region into the console however, i get:
region
'region' threw an exception of type 'System.NullReferenceException'
how is this possible?
EDIT: fixed a typo above, sorry about that. Something weird though, so if I reassign the value of regionArray to be an inline list, it still fails. But if I define a new inline list and iterate over that, the looping works fine.
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray = _utils.GetRegions(someParam); // this is not returning null
}
regionArray = new List<string>() {"china", "america"};
List<string> temp = new List<string>() {"foo", "bar"}
foreach (var region in regionArray)
{
// region still throws null reference exception
foreach (var tempVar in temp)
{
var c = tempVar; // this works. tempvar is never null.
}
var query = from dataSet in myDataSets
where dataSet.Location == region
select dataSet;
var queryResult = query.FirstOrDefault();
if (queryResult == null)
{
// do stuff
} else if (queryResult.State != States.Provisioned)
{
// do stuff
}
}
EDIT 2: So I tried iterating over the regionArray in the same way just before the logic above, and it worked fine.
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray = _utils.GetRegions(someParam); // this is not returning null
}
foreach (var region in regionArray)
{
var c = region; // this works
}
foreach (var region in regionArray)
{
// region throws null reference exception
var query = from dataSet in myDataSets
where dataSet.Location == region
select dataSet;
var queryResult = query.FirstOrDefault();
if (queryResult == null)
{
// do stuff
} else if (queryResult.State != States.Provisioned)
{
// do stuff
}
}
so most likely, it is not a problem with the moq object. based on #Iliar's suggestion, I will see if regionArray gets modified, but at first glance since regionArray is not used within the loop, my answer would be "no".
Update: I got around this issue by renaming the region looping variable to a different name. As it turns out, I was doing another foreach (var region ...) loop earlier in my code. I spoke to some senior colleagues as to why these 2 names would conflict with each other, and they said maybe it was some issue with symbols in VSCode and not really with my actual code. Thank you all for your help!
There was a lot of info in this thread, so just to summarize here are a few bulletpoints in case it is helpful to someone else in the future:
When debugging an XUnit test, I was seeing my looping variable in my foreach displaying the following info in the tooltip 'region' threw an exception of type 'System.NullReferenceException' Data [IDictionary]:{System.Collections.ListDictionaryInternal} HResult [int]:-2147467261 HelpLink [string]:null InnerException [Exception]:null Message [string]:"Object reference not set to an instance of an object." Source [string]:"9dd66c33104045bba27ad3fc9fb95185" StackTrace [string]:" at <>x.<>m0(<IngestEvents>d__13 <>4__this)" TargetSite [MethodBase]:{System.String <>m0(<IngestEvents>d__13)} Static members ....
even as I stepped INTO the loop, the tooltip for region was still showing the above, and when I typed region into the console, I got 'region' threw an exception of type 'System.NullReferenceException'.
The above 2 points led me to believe region was null. However, through #IVSoftware 's help, I verified that region was not actually null, because the assertion was passing.
I then looked at the rest of my code, and as a random guess, I tried renaming the looping variable region to something else. When I did, region was correctly set to the elements of the list.
Hi I really hope to be helpful. First I will answer your question "how is this possible?" and I think I can explain why your edited question with the inline list works. True, the GetRegions method returns a list that is not null. Sure, if you call GetType() on this it correctly identifies it as a "list of strings". I believe however, that the GetRegions method is returning a list that contains at least one null value. And you prove it out yourself when you added the edit, because you say this works:
regionArray = new List<string>() {"china", "america"};
But try making a list with three values like this where one of them is null and probably the loop will fail again.
regionArray = new List<string>() {"china", null, "america"};
This suggests a bug inside the GetRegions method is putting a null value into the list that it is returning. Adding these two lines at the beginning of your loop might go a long way to identifying the issue:
foreach (var region in regionArray)
{
// Look for this in the Visual Studio 'Output' window
System.Diagnostics.Debug.WriteLine(region == null ? "Null" : region);
// You believe that region is not null. So 'assert' that
// this evaluates to True and if it doesn't the debugger will break here.
System.Diagnostics.Debug.Assert(region != null, "Break on this line if region is null");
...
From what I can tell, I would look inside your GetRegions(someParam) method and see if it's inserting a null into the list somewhere. Good luck!
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray = _utils.GetRegions(someParam); // this is not returning null
}
this will override the regionArray instance, to the GetRegions instance, so creating new List<string> instance is useless.
What you want is :
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray.AddRange(_utils.GetRegions(someParam));
}
which is using this new instance, and add the resulted elements inside it.
If _utils.GetRegions(someParam) returns empty set, then regionArray will not be null, but it'll be empty regionArray.Count == 0.
this is also can be done using ToList as well:
var regionArray = _utils.GetRegions(someParam).ToList();
now , you need to check regionArray after that :
if(regionArray.Count == 0)
{
// do something
}
Or using Linq
if(!regionArray.Any())
{
// do something
}
if the collection is not empty then you can iterate through the list and validate each string inside this list before you process it:
foreach (var region in regionArray)
{
// check if the element is null or empty
// if true, will skip this element and go to the next one
if(string.IsNullOrEmpty(region)) { continue; } // go to the next iteration
// get the results
var queryResult = myDataSets.FirstOrDefault(x=> x.Location == region);
if (queryResult == null)
{
// do stuff
}
else if (queryResult.State != States.Provisioned)
{
// do stuff
}
}

LinqPad conversion error

i am getting an error on DuplicateOrder(TestOrder) as "cannot convert from tables.Order to int" even though the OrderID in the Orders table is an int
void DuplicateOrder(int orderId)
{
string methodName = MethodBase.GetCurrentMethod().Name;
try {
using (MSBLegacyContext db = new MSBLegacyContext())
{
var TestOrder = db.Orders.Where(i=>i.OrderID == orderId).FirstOrDefault();
DuplicateOrder(TestOrder);
}
}
catch (Exception ex)
{
Console.WriteLine(methodName, ex, string.Format("Test", orderId));
}}
what am i missing here?
Root cause, the FirstOrDefault in below line will return the either first order object or null.
var TestOrder = db.Orders.Where(i=>i.OrderID == orderId).FirstOrDefault();
So type of testOrder is order, but the below method call is expecting the int parameter.
DuplicateOrder(TestOrder);
That's the reason yor are getting -
cannot convert from tables.Order to int
To fix the issue, you need to add Select query in the Linq query and select the int column, something like below -
var TestOrder = db.Orders.Where(i=>i.OrderID == orderId).Select(s=> s.YourIntColumn).FirstOrDefault();
Edit:
After looking at you entire method and comments from others, you method call will definitely go to infinite loop. As you have not mentioned the purpose of this code, I am just assuming that you want to see whether a particular orderid is duplicate in the database or not. For that you can just use Count query and return the Boolean value. (not sure why do you have void in your method signature)
bool DuplicateOrder(int orderId) // changed from void to bool
{
using (MSBLegacyContext db = new MSBLegacyContext())
{
return db.Orders.Where(i=>i.OrderID == orderId).Count()>1; // returns true if more than 1 order found
}
}
If you have coded it correctly in your code, and if for a given orderId there were an Order, then your method would cause an infinite loop. Having said that, below is the correct way to get the int OrderId value:
using (MSBLegacyContext db = new MSBLegacyContext())
{
var TestOrder = db.Orders
.FirstOrDefault(i=>i.OrderID == orderId);
if (TestOrder != null)
{
var orderId = TestOrder.OrderId;
// ...
}
// else whatever you would do
}
If OrderId is a primary key, then you would use SingleOrDefault() instead of FirstOrDefault(). The difference is, if there is more than 1 entry in the database with given orderId, SingleOrDefault() would throw an error - and in the case of primary keys that is what you want.

Check if string already exist in Table

I want to check if the email that user entered already exist in Office table,take a look bellow what I have done so far, the problem is that officeEmail is always true, even though the entered email doesn't exist it's never returning NULL.
public static bool IsOfficeEmail(string email)
{
using (var data = Database)
{
data.ObjectTrackingEnabled = false;
var officeEmail = data.Offices.Where(a => a.Active && a.Email.Equals(email));
if (officeEmail != null)
return true;
}
return false;
}
Where will not return you null, but empty sequence, change it to:
var officeEmail = data.Offices.FirstOrDefault(a => a.Active && a.Email.Equals(email));
if (officeEmail != null)
return true;
FirstOrDefault will return default value (here null) it will not find queried value.
It is an option to use Any if you are not interested in email record:
public static bool IsOfficeEmail(string email)
{
using (var data = Database)
{
return data.Offices.Any(a => a.Active && a.Email.Equals(email))
}
}
You will not get email record if you will not use it anyway. Which approach you should use depends on what will you do with officeEmail, if you are just querying if it exists -> Any will be the best approach here. If you would like to get check for existing record and do something with it, FirstOrDefault will be better.
Alternativly if you really want to use .Where you can also check if the returned collection contains ANY elements:
if (officeMail.Any()) // ...
Or even shorter:
if (officeMail.Any(a => a.Active && a.Email.Equals(email))) // ...
If you want to ensure that there is exactly ONE item within your list matching your condition use .Single instead of .Any which will throw an exception if none or more then one item was found.
The actual reason for your check allways returning true is that .Where will return an enumerator even when no item matches the condition. Therefor the result is never null.

Correct query linq

I already use linq but search id only and it worked perfectly
var obj = (from VAR in db.infos
where VAR.id == 22
select new
{
title = VAR.title,
}).SingleOrDefault();
Label2.Text = obj.title.Trim();
If I try to search by location get a error
var obj = (from VAR in db.infos
where VAR.location.Trim() == "Lim"
select new
{
title = VAR.title.Trim(),
}).SingleOrDefault();
SearchJob.Items.Add(obj.title.Trim());
Label2.Text = obj.title;
Have a error in label2 line
Object reference not set to an instance of an object.
How do I fix it?
if (obj.title != null)
{
SearchJob.Items.Add(obj.title.Trim());
Label2.Text = obj.title;
}
Object reference not set to an instance of an object.
SOLUTION
Change SingleOrDefault() to FirstOrDefault()
You're doing some nasty stuff there, VERY bad habits. For instance this:
var obj = (from VAR in db.infos
where VAR.location.Trim() == "Lim"
select new
{
title = VAR.title.Trim(),
}).SingleOrDefault();
SearchJob.Items.Add(obj.title.Trim());
Label2.Text = obj.title;
Is a nonsense! Let me tell you why:
Always check the data BEFORE you insert it into your database, not AFTER. You're creating a lot of unnecessary overhead this way, which could be avoided altogether. Trim the data before, never after.
Next thing - you need only a single string value, yet you create an anonymous object. WHY? Do this instead:
string title = (from o in db.infos
where o.location == "Lim"
select o.title).SingleOrDefault();
Use SingleOrDefault if you expect a single result or none. However, if you expect multiple results and want only the first, use FirstOrDefault.
As you can see, I'm using o instead of VAR. It's true it doesn't really matter that much, BUT, it's never a good idea to use a word that's very similar to one of the reserved words (var).
If you get an exception Object reference not set to an instance of an object., it means that your query returned a null and you're trying to access a non-existing object. If your query may return null at some point, always check for null when accessing a member!
EDIT
if ( obj.title != null )
is bad too, because you need to check for null the object itself!
if (obj != null)
if you really want to use your bad approach.
I think the error occurred in the query
In first query you have source db.infos
In second you have source db.jobinfos
The source is changed
If we assign empty text to Label it will show, It looks like that obj.title does not exist or you are getting error in your query due to wrong source.
The obj is not returning title field. Check obj by debugging.
Try to skip exception :)
public static class LINQException {
public static void TryExample() {
var LsWithEx = from p in Enumerable.Range(0, 10) select int.Parse("dsfksdj");
var LsSkipEx = (from p in Enumerable.Range(0, 10) select int.Parse("dsfksdj")).SkipExceptions();
}
public static IEnumerable<T> SkipExceptions<T>(this IEnumerable<T> values)
{
using (var enumerator = values.GetEnumerator())
{
bool next = true;
while (next)
{
try
{ next = enumerator.MoveNext();}
catch
{ continue;}
if (next) yield return enumerator.Current;
}
}
}
}
var obj = (from VAR in db.infos
where VAR.location.Trim() == "Lim"
select new
{
title = VAR.title.Trim(),
}).SkipExce.SingleOrDefault();

What is the best way to check IQueryable result set is null

I just want to know what is the best way to check if an IQueryable result has no values.
eg. if we have a method like
public static IQueryable<Table> DisplayAll()
{
var db = new DataContext();
var list= from data in db.Table select data;
return list;
}
and then we do something like this
var list = DisplayAll();
if(list != null)
{
//do something --- in here even if the result set has no values it will
// go to this line. It just say `enumeration yielded no results`
}
Any possible way to check the result set has content or not??
Thanks
list will never be null with LINQ; it will simply represent an "empty collection" if need be. The way to test is with the Any extension method:
if (list.Any()) {
// list has at least one item
}
An exception will be thrown if IQueryable yeilds no result. I use:
using System.Data.Entity; //for Async support in EF
var tQ = await _tableRepository.DisplayAll();
try { return await tQ.ToListAsync(); }
catch { return null; }
to trap the exception and return null; or an empty List if you prefer,
catch { return new List<Table>(); }
Here is what works for me:
public IQueryable SomeFunc()
{
IQueryable result = Repo.SomeLinqQuery();
if (result.GetEnumerator().MoveNext() == false)
{
throw new Exception("Results empty");
}
return result;
}

Categories

Resources