Linq skip query if string is Null - c#

I am trying to implement a search function, but am running into problems when some of the fields are not filled in by a user.
string country = searchCountry.Text.ToLower();
string state = searchState.Text.ToLower();
var searchLocation= (from h in db.Locations where (!string.IsNullOrWhiteSpace(country) ? h.Country.ToLower().Contains(country):false)
&& (!string.IsNullOrWhiteSpace(state) ? h.State.ToLower().Contains(state) : false)
select h);
The problem is that when one of the strings is empty the searchLocation returns nothing and only works when both fields are filled in. I Have tried replacing the && with || but then it will get results, even if one of the search terms is not in the db.
Is there a way to do this, besides Filtering out null values in a linq search

This will return any locations where either the country is empty or it matches, and either the state is empty or it matches.
var searchLocation= (from h in db.Locations
where (string.IsNullOrWhiteSpace(country) || h.Country.ToLower().Contains(country))
&& (string.IsNullOrWhiteSpace(state) || h.State.ToLower().Contains(state))
select h);
It would help to have a bit more description of what you'd like to put in and get out, but this seems logical to me.
Either field would be optional, but it would filter results to include anything that matched all (one or two) filled in fields.
Of course, if you run this without any filters, it will return all locations. So keep that in mind if you're making requests to the database. If that's desired behavior, it might make sense to just pull all your data into a list beforehand, rather than querying every time anything is typed.

I believe you're overthinking this. Just validate the fields before searching:
string country = searchCountry.Text.ToLower();
string state = searchState.Text.ToLower();
if(string.IsNullOrWhitespace(state) || string.IsNullOrWhitespace(country))
{
//MessageBox.Show...
return;
}
var searchLocation= //query with validated fields
It's a very good idea to validate your input before trying to perform actions against it. And it makes your code more readable than combining the two.

Related

LINQ pull records from a database where string list is from a model

I have a database of strings that contain IDs. I need to pass that list into a LINQ query so I can pull the correct records.
model.SelectedDealers = db.dealers.Any(a => a.sdealer_name.Contains(UserToEdit.UserViewAccesses.Select(s => s.ViewReferenceNumber)));
SelectedDealers is of type dealers
ViewReferenceNumber should be a list of strings which should match sdealer_name
So essentially I am trying to find all of the dealers whos sdealer_name matches the list of sdealer_names I have in my UserToEdit.UserViewAccesses
I've tried moving parts around and switching them in different spots and can't seem to figure this out.
Any() is just a boolean indicating if there are any results. It doesn't actually return the results.
If I understand what you are after correctly, then this might work:
var dealerNames = UserToEdit.UserViewAccesses.Select(s => s.ViewReferenceNumber).ToList();
model.SelectedDealers = db.dealers.Where(a => dealerNames.Contains(a.sdealer_name));
So essentially I am trying to find all of the dealers whos
sdealer_name matches the list of sdealer_names I have in my
UserToEdit.UserViewAccesses
var dealersthatmatched = (from d in UserToEdit.UserViewAccesses.sdealer_names
where d == sdealer_name
select d).ToList()
Wish I could have made a comment instead, but as I don't have enough rep I can't. I wish I understood the requirement better, but you seem ready and able to try stuff so perhaps you find this useful.

How to search through a client Address details LINQ?

I am trying to figure out a way to search through a User's contact details.
User can have more than one Contact
Here is my code:
_usersRep.Find(r=>(string.IsNullOrEmpty(vm.PhoneNumber)
|| r.UserContacts
.Select(o => o.TelephoneNo)
.Contains(vm.PhoneNumber))
This should bring back me the user that any of its contact contains the PhoneNumber that I pass it to it. I actually tried to find where it should be equal but I could not get it worked.
I have checked on the database that this user has a contact object and that contac object phone number is the one that I search for but it does not bring me the user.
The relationship between User and UserContacts is one to many.
I also would like to ignore the search filter if the text is empty? But when I do not type anything it brings me all users.
I think you are looking for something like:
_usersRep.Where(r => r.UserContacts.Any(uc => uc.TelephoneNo == vm.PhoneNumber))
So restricting which users are returned (Where clause) based on whether the user has Any usercontacts with a matching number.
EDIT multiple conditions:
_usersRep.Where(r => r.UserContacts.Any(uc => uc.TelephoneNo == vm.PhoneNumber &&
uc.EmailAddress == vm.EmailAddress)) // etc
So the logic is, for each UserContact we test, if ALL the conditions are true in the lambda expression, then it passes the predicate, in which case as we are using the Any test, the userRep is selected. Hope this makes sense!
OK so if some of the fields can legitimately be empty, we should make sure the filter is defined if we do a compare, so combining in some nested ORs works here:
_usersRep.Where(r => r.UserContacts.Any(uc =>
(String.IsNullOrEmpty(vm.PhoneNumber) || uc.TelephoneNo == vm.PhoneNumber) &&
(String.IsNullOrEmpty(vm.EmailAddress) || uc.EmailAddress == vm.EmailAddress)))
Note that if all fields in vm are blank, this will bring back everything, as there is no restriction. If you don't want this, you should probably check before calling this query.
Explanation
Just to make it clear how this works. If we take the basic clause for each field:
(String.IsNullOrEmpty(vm.PhoneNumber) || uc.TelephoneNo == vm.PhoneNumber)
We are saying if part A or B is true, then for this field we have a match. Note that the || operator evaluates A first, and only evaluates B if A is false. So, in plain English, if String.IsNullOrEmpty(vm.PhoneNumber) is true (ie if the user doesn't enter query text for this field) then it is a match, no matter what the PhoneNumbers actually are. So therefore we only test uc.TelephoneNo == vm.PhoneNumber when something was specified for vm.PhoneNumber
So the above determines that for a single field we have a match (either because the user didn't enter a query for this field, or because they did, and the strings match). Now we use the && to ensure that every field we are checking is a match based on the above test.
Now because we do String.IsNullOrEmpty first for every field in our filter, if this is true for every field, based on the above logic, everything is a match. This makes semantic sense as well - if you don't enter any terms to restrict the search, you would expect to receive everything.
If the above is a problem in your case, as I said before I would check this before you execute the query, and tell the user that they must enter at least one search term to restrict the search.
The reason why you are getting all of the users when the search string is because of this
_usersRep.Find(r=>(string.IsNullOrEmpty(vm.PhoneNumber) || ... )
If the phone number string is null or empty then the find will always return true, giving you all of the users
you want
if(!string.IsNullOrEmpty(vm.PhoneNumber))
_usersRep.Find(r=> ... )
For the other problem, try trimming your string
if(!string.IsNullOrEmpty(vm.PhoneNumber))
_usersRep.Find(r=>r.UserContacts
.Select(o => o.TelephoneNo)
.Contains(vm.PhoneNumber.Trim()))
Besides those changes don't notice anything else that should be giving you problems.
Assume that vm.PhoneNumber is your search filter, add ! to String.IsNullOrEmpty check and change || to &&
_usersRep.Find(r=>(!string.IsNullOrEmpty(vm.PhoneNumber)
&& r.UserContacts
.Select(o => o.TelephoneNo)
.Contains(vm.PhoneNumber))

Using string methods in EF LINQ queries

I have a situation wherein two urls need to be compared, one coming in to the method and the other in the db. The one in the db may or may not be Url decoded and will have %20 for space and so on.
Here's the linq query in the method:
var Result = (from s in context.301Redirects
where s.IsDeleted == false && s.Status == true && HttpUtility.UrlDecode(s.OldURL).ToUpper() == HttpUtility.UrlDecode(OldURLPath).ToUpper()
select s.NewURL).FirstOrDefault();
return Result;
Inside the method I can UrlDecode the incoming param but what about the one in the db?
This one fails because EF will not recognize UrlDecode method and throw and exception saying so.
Is there a workaround?
You can bring the collection in memory, then perform the UrlDecode at that point by evaluating the query. Try:
var Result = (from s in context.301Redirects
where s.IsDeleted == false && s.Status == true)
.AsEnumerable()
.FirstOrDefault(HttpUtility.UrlDecode(s.OldURL).ToUpper() == HttpUtility.UrlDecode(OldURLPath).ToUpper();
return Result;
If your database table is huge though, I'd consider creating some sort of TRIGGER/update script to either URL encode or decode all records, that way you don't have to check at all, you just encode/decode the parameter passed in.
Do your adjustments before the query so that you have absolute values for comparisons in the query that align with the particular formats, and always check against the ones in the database, rather than transform them - so, this potentially includes using OR in your query, instead of pulling the whole thing into memory a la ToList.

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.

Check for items inside a Entity Framework linq result

I am trying to check to see if any results were returned from an entity framework query before acting upon it, I'm trying to use the code :-
var shoppingCartSessions = from c in context.ShoppingCartSessions where c.UserId == gUserID select c;
if (shoppingCartSessions.First() != null)
{
}
However I get the error
Sequence contains no elements
I have checked around stack and found that I can replace .First with .FirstOrDefault however I wanted to check if this is the correct way to be checking for existence of elements. Is there a better way rather than trying to fetch the item and then checking it?
Use Any():
var shoppingCartSessions = from c in context.ShoppingCartSessions
where c.UserId == gUserID
select c;
if (shoppingCartSessions.Any())
{
//not empty
}
Have you tried checking .Count() > 0 ?
EDIT:
As stated by Mahmoud Gamal, using Any() should render slightly better performance, since it will execute an EXISTS query, rather than a COUNT() on the DB, and you ultimately don't care about the exact amount.

Categories