c# .net 4.0 : nullable input string parameter and the lambda expressions - c#

I have a following method:
public IQueryable<Profile> FindAllProfiles(string CountryFrom, string CountryLoc)
{
return db.Profiles.Where(p => p.CountryFrom.CountryName.Equals(CountryFrom,StringComparison.OrdinalIgnoreCase));
}
Right now, it just filters by CountryFrom but I need to filter it by CountryLoc as well.
So how do I modify the Where filter?
Also, CountryFrom could be null or CountryLoc could be null. So how do I modify the method's signature to all the nullable input string parameter.
I know how to do this in SQL but I am not sure about lambda expressions or LINQ.
Thanks

Your question isn't actually LINQ-specific. You can put any boolean conditions inside the lambda that you want, such as:
p => p.CountryFrom.CountryName.Equals(...) && p.CountryLoc.CountryName.Equals(...)
To handle null values you can use the static string.Equals method instead, like this:
p => string.Equals(p.CountryFrom.CountryName, CountryName, StringComparison.OrdinalIgnoreCase)
If this starts getting too long you could always extract it into a method.

return db.Profiles
.Where(p => p.CountryFrom.CountryName.Equals(CountryFrom,
StringComparison.Ordinal.IgnoreCase) &&
p.CountryLoc.CountryName.Equals(CountryLoc,
StringComparison.Ordinal.IgnoreCase));
Sorry...there was no way to make that statement pretty.
Just remember you can use any boolean logic you'd like inside of the Where extension method. It's just as easy as it would be anywhere else.
Also, a string parameter can be null no matter what (it's a reference type) so you don't need to worry about making things nullable.

You'll want to use the logical and operator "&&" in your lambda expression to filter by both CountryFrom and CountryLoc. Ex
db.Profiles.Where(p => p.CountryFrom == CountryFrom && p.CountryLoc == CountryLoc);
In C# strings are reference types and therefore can be null. You can check for null values using
myString == null

Related

How to skip conditions in "Where" clause with multiple conditions?

I"m working on a WinfForms/C# software for automotive key management that's has a SQL query thats searchs in the table like that:
DataAdapter = SetAdapter($"SELECT * FROM keylist WHERE MANUFACTOR LIKE #manufactor AND KEYTYPE LIKE #type AND SERVICETYPE LIKE #service AND USER_ID = #_user");
So in the begginig I used to use the query directly in the search function but as the project grew, it ended up leaving it without performance, because the query was called directly on the remote server. So I decided to move everything to a list in C # and do the search with lambdas functions.
This is the function with lambda expression:
public List<Key> SearchFilter(string manufactor, string type, string service)
{
return _keys.Where(key => key.Manufactor == manufactor
&& key.Type == type
&& key.ServiceType == service).ToList();
}
The problem is:
In the SQL syntax, when you leave one or more fields, it automatically ignores and checks for the other, but when I use Where <> in the LINQ for example, it ends up returning null or items that do not satisfy conditions and returning other objects.
When I leave one or two of the parameters null, it returns no value. By the way, if I use || instead of && it returns undesirable values.
Is there a way to check if the condition is null and skip to the next clause and return only the values that were passed?
if I understand correctly, I think I should make several "Where" conditions, one for each condition, that is:
return _keys.Where(key => manufactor != string.Empty ? key.Manufactor == manufactor ? key.Manufactor != string.Empty)
.Where(key => key.Type == type)
.Where(key => key.ServiceType == service)
.ToList();
You can also "exclude" or "include" filters if there is value to filter as I did with "key.Manufactor".

Combining expression trees

I have the following expression:
public Expression<Func<T, bool>> UserAccessCheckExpression<T>(int userId) where T : class
{
return x => (IsAdmin || userId == CurrentUserId || userId == 0);
}
Then I want to apply this filter to several collections (IQueryable) like this one:
return tasks
.Where(t => t.TaskUsers
.Any(x => UserAccessCheckExpression<TaskUser>(x.User) && x.SomeBool == true));
I'm getting the following error while doing so:
Error 40 Cannot implicitly convert type System.Linq.Expressions.Expression<System.Func<TaskUser,bool>> to bool
I can't use workaround with interface inheritance (like TaskUser inherits interface with int UserId property (where T : IHasUserId)) since I want to combine logic.
The problem is that your UserAccessCheckExpression() method is returning an Expression while the Any() method is expecting a boolean.
Now, you can get your code to compile by compiling the Expression and invoking the method (using UserAccessCheckExpression<TaskUser>(x.User).Compile().Invoke(x.User)) but that would obviously fail on runtime because Linq-to-Entities wouldn't be able to translate your Any() to a store query as it no longer contains an Expression.
LinqKit is aiming to solve this problem using its own Invoke extension method that while letting your code compile, will make sure your Expression will get replaced back to its original form using another extension method named AsExpandable() that is extending the entity set.
Try this:
using LinqKit.Extensions;
return tasks
.AsExpandable()
.Where(t => t.TaskUsers.Any(
x => UserAccessCheckExpression<TaskUser>(x.User).Invoke(x)
&& x.SomeBool == true));
More on LinqKit
Yeah, so, you can't do that. There's a difference between an Expression<> and a Func<>. You're trying to use the UserAccessCheckExpression as a func. I'm not sure what you're trying to do, but you can compile it to a func and then use it sorta like you are:
var expr = UserAccessCheckExpression<TaskUser>(x.User);
var func = expr.Compile();
// Later use it like ...
var result = func();
But I expect you're using this with EF or Linq2Sql? That being the case you'll need to rewrite the expression. It can be done by hand (not easy) or, better, use a tool like PredicateBuilder.

logical short-circuit and lambdas

I have the following lambda expression:
response = allDescendants
.Where(n =>
n.Caption.Contains(query) ||
n.Identifier.ToString().Contains(query) ||
n.Type.ToString().Contains(query) ||
n.Path.Contains(query) ||
n.Description.Contains(query) ||
(n.KeyWords != null && n.KeyWords.Any(kw => kw.Contains(query))) ||
n.SubType.Contains(query) ||
n.GroupingBy.Contains(query)
).ToList();
in the class definition the keyWord field is set to null:
private string[] keyWords = null;
public string[] KeyWords
{
get { return keyWords; }
set { keyWords = value; }
}
The line (n.KeyWords != null && n.KeyWords.Any(kw => kw.Contains(query))) throws a NullReferenceException because the the KeyWord field is null, but I was under the impression that since the check for null happened before the lambda, the entire expression should short-circuit to false. Is this something specific to do with lambdas or something else I'm not getting?
Edit:
I have found the culprit, it was a constructor that sets the string array to string[1] instead of null.
The debugger just marks that whole line. n.KeyWords was not null since, indeed, && short-circuits. (Or, that KeyWords property returns non-null the first time and null the second time it is called!)
Look at the call stack to see in what method the crash actually happened. The lambda will be on top and use can use the debugger to examine the value of kw which will be null.
As everyone in the comments suggested, I have looked for a code path that sets elements of my array to null instead of the entire array and have found it. It now sets the entire array to null and the code works as intended.

Why does EF not return any results when comparing null variable?

I'm having an issue selecting data in my data context in Entity Framework and I've narrowed it down to querying for null values. I have a method like this:
public void DoStuff(int? someInt)
{
var someData = dataContext.MyEntities.Where(x => x.SomeProperty == someInt);
// someData always yields no results if someInt is null, even though
// there are rows in the table that have null for that column.
}
The above method fails if someInt is null. But this line works:
var someData = dataContext.MyEntities.Where(x => x.SomeProperty == null);
Why do I get data in the second one but not the first one?
I guess, then, that it is generating and using a SQL query of the form that expects a non-null value:
where x.SomeProperty = #param
Instead of the SQL to show the c# null-equality semantic:
where x.SomeProperty is null
(the key point here being that in c#, null equals null; in ANSI-SQL, null neither equals null nor (confusingly) not-equals null - different syntax is need to test nulls)
I've seen LINQ-to-SQL do the same thing, and agree that it is counter-intuitive. The only suggestion I have is: test the candidate parameter for null yourself and do the constant/literal == null test instead. It would also probably be able to do the same by inspecting and expression tree and re-writing it, if you are into expression trees - but special-casing the null is simpler.
someInt isn't null on its own. someInt.Value would be null.

Linq to objects when object is null VS Linq to SQL

I have this Linq to object query:
var result = Users.Where(u => u.Address.Country.Code == 12)
I get an exception if the Address or the Country are null.
Why this query doesn't check if the address is null and just after that procced?
This way I won't need to write this terrible query:
var result = Users.Where(u => u.Address != null &&
u.Address.Country != null &&
u.Address.Country.Code == 12)
In Linq to SQL the first query wiil do the job(from other reasons of course).
Is the a way to avoid the "null checks" in linq to object?
Unfortunately, "null" is treated inconsistently in C# (and in many other programming languages). Nullable arithmetic is lifted. That is, if you do arithmetic on nullable integers, and none of the operands are null, then you get the normal answer, but if any of them are null, you get null. But the "member access" operator is not lifted; if you give a null operand to the member access "." operator, it throws an exception rather than returning a null value.
Were we designing a type system from scratch, we might say that all types are nullable, and that any expression that contains a null operand produces a null result regardless of the types of the operands. So calling a method with a null receiver or a null argument would produce a null result. That system makes a whole lot of sense, but obviously it is far too late for us to implement that now; millions upon millions of lines of code have been written that expects the current behaviour.
We have considered adding a "lifted" member access operator, perhaps notated .?. So you could then say where user.?Address.?Country.?Code == 12 and that would produce a nullable int that could then be compared to 12 as nullable ints normally are. However, this has never gotten past the "yeah, that might be nice in a future version" stage of the design process so I would not expect it any time soon.
UPDATE: The "Elvis" operator mentioned above was implemented in C# 6.0.
No, it is a null reference exception just like accessing var x = u.Address.Country.Code; would be a NullReferenceException.
You must always make sure what you are de-referencing is not null in LINQ to objects, as you would with any other code statements.
You can do this either using the && logic you have, or you could chain Where clauses as well (though this would contain more iterators and probably perform slower):
var result = Users.Where(u => u.Address != null)
.Where(u.Address.Country != null)
.Where(u.Address.Country.Code == 12);
I've seen some Maybe() extension methods written that let you do the sort of thing you want. Some people do/don't like these because they are extension methods that operate on a null reference. I'm not saying that's good or bad, just that some people feel that violates good OO-like behavior.
For example, you could create an extension method like:
public static class ObjectExtensions
{
// returns default if LHS is null
public static TResult Maybe<TInput, TResult>(this TInput value, Func<TInput, TResult> evaluator)
where TInput : class
{
return (value != null) ? evaluator(value) : default(TResult);
}
// returns specified value if LHS is null
public static TResult Maybe<TInput, TResult>(this TInput value, Func<TInput, TResult> evaluator, TResult failureValue)
where TInput : class
{
return (value != null) ? evaluator(value) : failureValue;
}
}
And then do:
var result = Users.Where(u => u.Maybe(x => x.Address)
.Maybe(x => x.Country)
.Maybe(x => x.Code) == 12);
Essentially, this just cascades the null down the chain (or default value in the case of a non-reference type).
UPDATE:
If you'd like to supply a non-default failure value (say Code is -1 if any part is null), you'd just pass the new failure value into Maybe():
// if you wanted to compare to zero, for example, but didn't want null
// to translate to zero, change the default in the final maybe to -1
var result = Users.Where(u => u.Maybe(x => x.Address)
.Maybe(x => x.Country)
.Maybe(x => x.Code, -1) == 0);
Like I said, this is just one of many solutions. Some people don't like being able to call extension methods from null reference types, but it is an option that some people tend to use to get around these null cascading issues.
Currently, however, there is not a null-safe de-reference operator built into C#, so you either live with the conditional null checks like you had before, chain your Where() statements so that they will filter out the null, or build something to let you cascade the null like the Maybe() methods above.

Categories

Resources