short circuting linq queries thowing null error - c#

Ive been having some trouble trying to get this linq statement to work. I am setting up a search using linq queries. What i want to do is if a search is null or empty, have it ignore that part of the filtering. So what i have set up is many where clauses that short circuit the where clause like so:
tvContent.LoadContent(
Live.Ringtones
.Where(x => cbSeller.SelectedValue== null ||
x.Property.SellerID == (int)cbSeller.SelectedValue)
.Where(x => cbProperty.SelectedValue==null ||
x.PropertyID == (int)cbProperty.SelectedValue)
.Where(x => string.IsNullOrEmpty(tbContentID.Text) ||
x.RingtoneID == ContentID)
.Where(x => string.IsNullOrEmpty(tbContentName.Text) ||
x.RingtoneName == tbContentName.Text).ToList());
But when I do this I keep getting null reference issues.
cbProperty, is empty, and selectedValue does show up null when I debug, but it still says there's a null reference issue. What am I doing wrong?

Why are you putting an invariant into the where clauses?
var ringtones = Live.Ringtones;
if (cbSeller.SelectedValue!= null)
ringtones = ringtones.Where(x=> x.Property.SellerID
== (int)cbSeller.SelectedValue);
if (cbProperty.SelectedValue!= null)
ringtones = ringtones.Where(x=> x.PropertyID
== (int)cbProperty.SelectedValue);
if(!string.IsNullOrEmpty(tbContentID.Text))
ringtones.Where(x=> x.RingtoneID == ContentID)
if(!string.IsNullOrEmpty(tbContentName.Text) )
ringtones.Where(x => x.RingtoneName == tbContentName.Text)
tvContent.LoadContent(ringtones.ToList());

Related

Why am I getting a "Sequence contains no matching element" error when using .Any

I have a .Any() Linq Method:
db.MyTable.Any(x => x.Year == MyObj.Year && x.Quarter == MyObj.Quarter && x.Week == MyObj.Week)
That is returning the error:
System.InvalidOperationException occurred
HResult=0x80131509
Message=Sequence contains no matching element
Source=EntityFramework
However the MSDN documentation states that the .Any method returns "true if the source sequence contains any elements; otherwise, false."
Why is this method throwing the exception instead of returning False?
With this little code it is fairly difficult to see what the cause is. It certainly is not in this part of the code.
Try to do some debugging, use the debugger to check all values, or write some Debugging statements before you perform your function:
// Check myObj
MyObjectType myObj = ... // instead of var, so you are certain you have the right type
Debug.Assert(myObj != null);
// only if Year, Quarter, Week are classes:
Debug.Assert(myObj.Year != null);
Debug.Assert(myObj.Quarter != null);
Debug.Assert(myObj.Week != null);
// check your db:
Debug.Assert(db != null);
Debug.Assert(db.MyTable != null);
int count1 = db.MyTable.Count();
int count2 = db.MyTable
.Where(x => x.Year == MyObj.Year
&& x.Quarter == MyObj.Quarter
&& x.Week == MyObj.Week)
.Count();
bool hasAny = db.MyTable
.Where(x => x.Year == MyObj.Year
&& x.Quarter == MyObj.Quarter
&& x.Week == MyObj.Week)
.Any();
// if all this works, your statement should also work
hasAny = db.MyTable
.Any(x => x.Year == MyObj.Year
&& x.Quarter == MyObj.Quarter
&& x.Week == MyObj.Week);
Is hard to see, with your example but probably you must check if you have Null values in "MyTable" and the datatypes of MyTable.Year,MyTable.Quarter and MyTable.Week match with the sames in MyObj...

Null Reference exception in FirstOrDefault C#

I have this line:
myobject.Ada = result.FirstOrDefault(m => m.Name == "Ada No").Value;
Sometimes result doesn't have "Ada No" and I get
Object reference not set to an instance of an object.
I wrote an if statement to avoid null reference exception :
if(result.FirstOrDefault(m => m.Name == "Ada No").Value != null)
{
myobject.Ada = result.FirstOrDefault(m => m.Name == "Ada No").Value;
}
But it didn't work either. How can I avoid this exception in this piece of code? How can I write if Ada No exists, work, if not don't work? Thanks.
FirstOrDefault will return null if there is not any object which meets the condition. And the exception will be thrown when the code is trying to access a member of a reference type variable that is set to null. So, you must check if the object's value is null or not before accessing it.
You can use null-propagation operator if you are using C# 6.0:
myobject.Ada = result.FirstOrDefault(m => m.Name == "Ada No")?.Value;
Or if you are using lower versions:
var firstObj = result.FirstOrDefault(m => m.Name == "Ada No");
if(firstObj != null)
{
myobject.Ada = firstObj.Value;
}
The other solution would be to check with Any if any member is existing that consists of Name equal to "Ada No"
Be aware that result isn't null either!
But the null propagation way would be less to write, so it depends on you preference how you want to read your code and if it is some performance critical piece of code
if(result != null && result.Any(m => m.Name == "Ada No"))
{
myobject.Ada = result.FirstOrDefault(m => m.Name == "Ada No").Value;
}

LINQ query automatic List Populate vs ToList in EF 6.1

I am using visual studio 2013 .Here a strange thing happen but i cannot find the answer .I have following LINQ query
var tvAssingedJobs = dbEntities.Tv_ProductService
.Where(i => i.ServiceManagerId == userId
&& i.TechnicianId != null
&& (i.ProductServiceStatus != "C"
&& i.ProductServiceStatus != "QP")
);
foreach (var assingedJob in tvAssingedJobs)
{
var requision = assingedJob.Tv_SparePartsRequision
.FirstOrDefault(i => i.RecommendedUserId == userId
&& i.TechnicianId == assingedJob.TechnicianId
);
}
Here i can iterate but i did not convert it to list .Is this query supposed to be like this
var tvAssingedJobs = dbEntities.Tv_ProductService
.Where(i => i.ServiceManagerId == userId
&& i.TechnicianId != null
&& (i.ProductServiceStatus != "C"
&& i.ProductServiceStatus != "QP")
).ToList();
Both working fine.So my question in which to use ? Is first query may cause exception or create some performance issue in production in future ?

Proper way to use LINQ for this type of query?

I was originally using a foreach loop and then for each element in the loop, I perform a LINQ query like so:
foreach (MyObject identifier in identifiers.Where(i => i.IsMarkedForDeletion == false))
{
if (this.MyEntities.Identifiers.Where(pi => identifier.Field1 == pi.Field1 && identifier.Field2 == pi.Field2 && identifier.Field3 == pi.Field3).Any())
{
return false;
}
}
return true;
Then I modified it like so:
if (identifiers.Any(i => !i.IsMarkedForDeletion && this.MyEntities.Identifiers.Where(pi => i.Field1 == pi.Field1 && i.Field2 == pi.Field2 && i.Field3 == pi.Field3).Any()))
{
return false;
}
return true;
My question is this still the wrong way to use LINQ? Basically, I want to eliminate the need for the foreach loop (which seems like I should be able to get rid of it) and also make the DB query faster by not performing separate DB queries for each element of a list. Instead, I want to perform one query for all elements. Thanks!
You can change your code in this way, and it will be converted to SQL statement as expected.
To prevent runtime errors during transformation, it will be better to save DBSet to the IQueryable variable; identifiers should be IQueryable too, so you should change your code into something like this (to be honest, Resharper converted your foreach in this short labda):
IQueryable<MyObject2> identifiers = MyEntities.Identifiers.Where(i => i.IsMarkedForDeletion == false);
IQueryable<MyObject2> ids = MyEntities.Identifiers.AsQueryable();
return identifiers.All(identifier => !ids.Any(pi => identifier.Field1 == pi.Field1 && identifier.Field2 == pi.Field2 && identifier.Field3 == pi.Field3));
If identifiers is in memory collection you can change code in this way (hope that fields are string):
IQueryable<MyObject2> ids = MyEntities.Identifiers.AsQueryable();
string[] values = identifiers.Where(i => i.IsMarkedForDeletion == false).Select(i => String.Concat(i.Field1, i.Field2, i.Field3)).ToArray();
return !ids.Any(i => values.Contains(i.Field1 + i.Field2 + i.Field3));
Unfortunately your modified version will be executed exactly the same way (i.e. multiple database queries) as in the original foreach approach because EF does not support database query with joins to in memory collection (except for primitive and enumeration type collections), so if you try the most logical way
bool result = this.MyEntities.Identifiers.Any(pi => identifiers.Any(i =>
!i.IsMarkedForDeletion &&
i.Field1 == pi.Field1 && i.Field2 == pi.Field2 && i.Field3 == pi.Field3));
you'll get
NotSupportedException: Unable to create a constant value of type 'YourType'. Only primitive types or enumeration types are supported in this context.
The only way to let EF execute a single database query is to manually build a LINQ query with Concat per each item from in memory collection, like this
IQueryable<Identifier> query = null;
foreach (var item in identifiers.Where(i => !i.IsMarkedForDeletion))
{
var i = item;
var subquery = this.MyEntities.Identifiers.Where(pi =>
pi.Field1 == i.Field1 && pi.Field2 == i.Field2 && pi.Field3 == i.Field3);
query = query != null ? query.Concat(subquery) : subquery;
}
bool result = query != null && query.Any();
See Logging and Intercepting Database Operations of how to monitor the EF actions.
I would use it as follows:
if (identifiers.Where(i => !i.IsMarkedForDeletion &&
this.MyEntities.Identifiers.Field1 == i.Field1 &&
this.MyEntities.Identifiers.Field2 == i.Field2 &&
this.MyEntities.Identifiers.Field3 == i.Field3).Any()))
{
return false;
}
return true;
I hope this helps. Even though it is more to type out, it is more understandable and readable then using multiple 'where' statements.

Using Linq to filter by List<ListItem>

I am trying to extend my linq query with additional search criteria to filter the data by sending also a List<Listitem> to the function for processing. The List can contain 1 or more items and the objective is to retreive all items which match any criteria.
Since i am sending several search criteria to the function the goal is to make a more accurate filter result the more information i am sending to the filter. If one or several criterias are empty then the filter will get less accurate results.
Exception is raised every time i execute following code, and I cant figure out how to solve the using statement to include the List<ListItem>. Appreciate all the help in advance!
Exception: Unable to create a constant value of type 'System.Web.UI.WebControls.ListItem'. Only primitive types or enumeration types are supported in this context.
using (var db = new DL.ENTS())
{
List<DL.PRODUCTS> products =
(from a in db.PRODUCTS
where (description == null || description == "" ||
a.DESCRIPTION.Contains(description)) &&
(active == null || active == "" || a.ACTIVE.Equals(active, StringComparison.CurrentCultureIgnoreCase)) &&
(mID == null || mID == "" || a.MEDIA_ID == mID) &&
(mID == null || objTypes.Any(s => s.Value == a.OBJECTS)) //Exception here!
select a).ToList<DL.PRODUCTS>();
return products;
}
Pass collection of primitive values to expression:
using (var db = new DL.ENTS())
{
var values = objTypes.Select(s => s.Value).ToArray();
List<DL.PRODUCTS> products =
(from a in db.PRODUCTS
where (description == null || description == "" || a.DESCRIPTION.Contains(description)) &&
(active == null || active == "" || a.ACTIVE.Equals(active, StringComparison.CurrentCultureIgnoreCase)) &&
(mID == null || mID == "" || a.MEDIA_ID == mID) &&
(mID == null || values.Contains(a.OBJECTS))
select a).ToList<DL.PRODUCTS>();
return products;
}
That will generate SQL IN clause.
Note - you can use lambda syntax to compose query by adding filters based on some conditions:
var products = db.PRODUCTS;
if (!String.IsNullOrEmpty(description))
products = products.Where(p => p.DESCRIPTION.Contains(description));
if (!String.IsNullOrEmpty(active))
products = products.Where(p => p.ACTIVE.Equals(active, StringComparison.CurrentCultureIgnoreCase)));
if (!String.IsNullOrEmpty(mID))
products = products.Where(p => p.MEDIA_ID == mID);
if (mID != null)
products = products.Where(p => values.Contains(p.OBJECTS));
return products.ToList();
Linq isn't able to convert the predicate on ListItem to something useful to Sql.
I would suggest that you pre-project the values of the ListItems into a simple List<string> before using this with Contains (which is converted to IN)
var listValues = objTypes.Select(_ => _.Value).ToList();
List<DL.PRODUCTS> products = ...
listValues.Contains(a.OBJECTS))

Categories