Identity Filter Linq .Where - c#

I need to provide a null where clause that has no effect.
Currently I have:
f=>{f!=null;}
However that doesn't really look right. If I were to Select clients, I use
.Select(clients => clients)
With my filter I also get a warning about not all code paths returning a result.

Just return true:
foo.Where(f => true)
Your lambda expression doesn't work for three reasons:
You're trying to use f != null as a statement, which it isn't.
You don't have a return value.
It would reject null values.
The first two can be fixed by removing the braces:
foo.Where(f => f != null)
The last point means it's not really a no-op filter, which is what I guess you meant by "identity filter". Whether it's what you really want or not though, I can't say.

Related

Explain LINQ All() expression

I was wondering if any one can help explain this expression with two lists,
originalForm.FormItems.Where(x =>
newForm.FormItems.All(y => y.ItemId != x.ItemId));
I think it is supposed to return items that are in originalForm but not in newForm, however, when I try and understand it myself I think it's saying the opposite. If someone could break it down for me, it'd be a big help.
Thanks in advance :)
An equivalent of your code that is a little more clear is this code using Except:
var l = originalForm.Select(x => x.ItemId).Except(newForm.FormItems.Select(y => y.ItemId));
This will only get you the item IDs. You can look the actual items back later on if you need them:
originalForm.Where(x => l.Contains(x.ItemId));
Your code "where not any" is "where none", which is the same as "except".
You are correct, that is what it does, and it is a strange implementation.
I would use Any instead of All:
originalForm.FormItems.Where(x =>
!newForm.FormItems.Any(y => y.ItemId == x.ItemId));
I think it's much more readable.
The All method will return true if all of the elements in the IEnumerable returns true for the given predicate.
Taken from the source code of Enumerable.cs, here is how it's implemented.
public static bool All<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
foreach (TSource element in source) {
if (!predicate(element)) return false;
}
return true;
}
So basically, it will return true only if all the elements of the newForm.FormItems have an ItemId property that is different then the current element from originalForm.FormItems being tested currently in the Where.
The Any method is the exact opposite - it will return true if at least one of the elements in the IEnumerable returns true.
There is another option which is even simpler - and that's to use Contains:
originalForm.FormItems.Where(x => !newForm.FormItems.Contains(y => y.ItemId == x.ItemId);
You can use a negation of the Any expression while checking for equality. Like that it might not always check all the items of the second collection.
originalForm.FormItems.Where(x =>
!newForm.FormItems.Any(y => y.ItemId == x.ItemId));
Any will return as soon as it find 1 item that match the expression. So this create 2 scenarios.
Scenario 1 : If the original id exist in the second list the Any will find the first occurrence and return true, Then it get negated to false and so it doesn't pick the item in the return results.
Scenario 2 : If the original id does not exist in the second list the Any will test all the items of the second list and wont find any so it will return false, Then it get negated to true and so the item is in the return results.
The set operation you are looking for is subtraction, which is implemented by LINQ's Except method. You want the form items in Form 1 minus the items in form 2 based on their IDs.
In SQL you'd use the NOT IN (...) clause to achieve the same
When you don't have an explicit subtraction operator, you cam implement subtraction by including ALL items that don't match a mismatch condition (like your code), or excluding ANY that match an equality condition.
The most common version of Enumerable.Except compares objects using their equality operators. You can use this to find the unique ItemIDs and then retrieve the form items.
Another overload allows you to specify a comparer. Unfortunately there's no built-in way to specify a comparison predicate, so you have to create a custom comparer class that inherits from eg EqualityComparer and compares only the ItemId properties.
A better option is to use the ExceptBy that allows you to specify the key used for comparison, eg :
var uniqueItems=originalForm.FormItems
.ExceptBy(newForm.FormItems,it=>it.ItemId);
You can add MoreLINQ as a binary NuGet package or you can add the code to your project by adding the MoreLinq.Source.MoreEnumerable.ExceptBy source package

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))

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.

Why is this if/then statement returning as true?

I have a rather ugly service job that runs through a legacy database and compares it to our production database:
if (vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number) != null) {
var oldDbContractItem = vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).First();
// check to see if there were changes
if (oldDbContractItem.DateStamp != vendorContractItem.Date_Stamp)
{
oldDbContractItem.Update(vendorContractItem);
}
}
I will get an error on var oldDbContratItem, "Sequence contains no elements", yet I just did a != null check. This must be simple, what's going on?
If I could teach people just one thing about LINQ it's this: the value of a query expression is an object that represents the query, not the results of the query. Fundamentally that's your problem; you're treating the query as its results. A query isn't a result any more than a restaurant is a club sandwich. A restaurant is a device which produces club sandwiches; a query is a device that produces results.
This is the test against null you are doing:
vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number) != null
That will always be true; That will always return at least an empty sequence... never a null.
You might be meaning to test that its length is greater than 0?
There's an easier way, though, IMO. Call FirstOrDefault() instead of First() and leave out the pre-test completely. Then instead, test if the result of FirstOrDefault() is null.
var oldDbContractItem = vendorContract.Item
.Where(x => x.ItemNumber == contractItem.Item_Number).FirstOrDefault();
if(oldDbContractItem != null) //would be null if there are no items
{
// check to see if there were changes
if (oldDbContractItem.DateStamp != vendorContractItem.Date_Stamp)
{
oldDbContractItem.Update(vendorContractItem);
}
}
}
Because your query returned a container, it just happened to be empty, the null check is on the return not what the return contains.
try this instead...
if (vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).Any())
{
.....
}
Don't run the query twice. It's inefficient and may introduce a race condition into your code. Also, your logic is much better supported by either using IEnumerator<T> directly, or with a foreach loop.
Use either:
var result = vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number).GetEnumerator();
if (result.MoveNext) {
var oldDbContractItem = result.Current;
// ...
}
or
foreach (var oldDbContractItem in vendorContract.Item.Where(x => x.ItemNumber == contractItem.Item_Number)) {
// ...
break;
}
A sequence with no elements is still an object.
Where can return a non-null value, but still resolve to a sequence containing no elements. In your failing statement you are using something else, which is Where().First(). That will be null if the sequence from Where is indeed empty.
There is difference between null and an empty sequence (e.g. something similar to new List<T>()). What you want to do is to use Any() to check whether the sequence contains any elements, or rather replace First() with FirstOrDefault(), which returns null if the sequence contains no element. (If you use that, make sure that null is not a valid value that could be returned by First()).
After using a fix from the accepted answer, you can further debug the LINQ situation (if need be) by using the following steps. LINQ is an exciting technology but takes a while to wraps ones' head around it - a bit of a paradigm shift I would say. Eric's answer hit the nail on the head because he likely helped build the stuff!
Debugging Steps for LINQ
To deal with the issue of no results from the second statement change .First() to .FirstOrDefault() If nothing is found it will return the default value of the data type - if the data type is a class it will return a null value. Your second statement should then work with a null check too and without error.
Then you can debug your LINQ statement to find out why it's doing what it does.
if using LINQ to SQL, Intellisense in Visual Studio 2010 will show you the SQL generated when you hover over a query variable (not the result of a query). If you need the visualizer for VS 2008 it's here
Similarily if you're using LINQ to Entity Framework, you can get the generated SQL using the visualizer plugin here.
I always take the generated SQL from these tools, paste it directly into a query window and run it there. It will show you the empty set you're getting back and if that's a problem you can further debug it in this manner of visualizing the generated statements.

Conditional shortcuts in LinqToSql query

Here's a little LinqToSql GOTCHA:
// Returns the number of counties in a state,
// or all counties in the USA if the state is null
public static int CountCounties(State s) {
var q =
from cy in County.GetTable() // my method to get the ITable
where (s == null || s.Code == cy.StateCode) // shortcut OR operator, right...?
select cy;
return q.Count();
}
Guess what - if you pass a null State object to this method, you get a null reference exception! It seems that LinqToSql doesn't use the || shortcut operator as a shortcut!
Answer credit goes to whoever proposes the best explanation & workaround for this.
If it's linq to sql then remeber that Linq is just parsing your query into SQL.
It is therefore sending both of your where clauses to the database, hence the exception. I dont find this surprising really, though it is arguably wrong.
You will just have to do an independant check.
if (!string.isNullOrEmpty(state.statecode)
q = q.where( s => s.code == state.statecode
This is not related to LINQ in general. In this case, the LINQ-to-SQL provider tries to parse the your lambda expression and make it a TSQL query. It cannot make too many assumptions based on your expression since it's trying to delegate most of the work to the database.
Long story short, the provider simply cannot translate it to SQL.

Categories