I want to create an if/else statement in this case :
var controls= _listControls
.Select(
control => new
{
Name,
Quantity,
Valid = isValid
? sp.GetInfos(ID).SerialNumber.ToString()
: string.Empty
})
.ToList();
I just want to check if sp.GetInfos(ID).SerialNumber.ToString()is null in the statement and say if it's not null ? DoThings() : DoThings() .
Thanks
You can use ternary operators inside other ternary statements like this
Valid = isValid
? string.IsNullOrEmpty(sp.GetInfos(ID).SerialNumber?.ToString())
? string.Empty
: sp.GetInfos(ID).SerialNumber.ToString()
: string.Empty
N.B. The SerialNumber?.ToString() is a null conditional operator, you can read more about it here
You can encapsulate all logic in a helper method. As I consider it's more readable and also you are able to test this method separately.
string Valid(....)
{
if (isValid)
{
if (sp.GetInfos(ID).SerialNumber == null)
{
....
}
else
{
..
}
}
return string.Empty;
}
And then simply call this method inside LINQ query
var controls = _listControls
.Select(
control => new
{
Name,
Quantity,
Valid = Valid (...)
})
.ToList();
Related
I have this query:
if(!string.IsNullOrEmpty(code) && !string.IsNullOrEmpty(name))
{
return this.context.Table.Where(
x => EF.Functions.Contains(x.Code, $"\"{code}\"")
&& EF.Functions.Contains(x.Name, $"\"{name}\""));
}
else if(string.IsNullOrEmpty(code) && !string.IsNullOrEmpty(name))
{
return this.context.Table.Where(x => EF.Functions.Contains(x.Name, $"\"{name}\""));
}
else
{
return this.context.Table.Where(x => EF.Functions.Contains(x.Code, $"\"{code}\""));
}
I tried to do it again using the ternary operators then check if the string is not null or empty and if so add the where clause or not
I tried such a thing but obviously expects that after the "?" there is the alternative of ":"
return this.context.Table.Where(
x => !string.IsNullOrEmpty(code)
? EF.Functions.Contains(x.Code, $"\"{code}\"")
&& !string.IsNullOrEmpty(name)
? EF.Functions.Contains(x.Name, $"\"{name}\""));
Since unlike the example in my case I have to check 8 different input parameters that if not passed must not be used in the where for the controls, I wanted to avoid filling the code of many if cases and rewriting the query n times for the different combinations, is there a way or should I resign myself?
You can just return true for any you don't want to check for like below
!string.IsNullOrEmpty(code) ? EF.Functions.Contains(x.Code, $"\"{code}\"") : true;
This means if the string is null or empty then it will return true which should provide the behaviour you're expecting.
Do not use ternary operators for combining query. EF will create non optimal SQL.
Usually such task is done in the following way:
var query = this.context.Table.AsQueryable();
if (!string.IsNullOrEmpty(code))
{
query = query.Where(
x => EF.Functions.Contains(x.Code, $"\"{code}\""));
}
if (!string.IsNullOrEmpty(name))
{
query = query.Where(
x => EF.Functions.Contains(x.Name, $"\"{name}\""));
}
var result = query.ToList();
The situation
I have a method that takes in a POCO. This POCO is like the following
private class SearchCriteria
{
public string name get;set;
public string age get;set;
public string talent get;set;
..
....
}
The method basically has a query to the db , that uses the above criteria.
public void query(SearchCriteria crit)
{
if(crit.name!=null && crit.age!=null && crit.talent !=null)
{
dbContext.Students.Where(c=>c.name ==crit.name && c.age==crit.age...)
}
else if(crit.name !=null && crit.age!=null)
{
}
else if(....
{
}
As you can see there is a definite problem above , where in, in case of large number of criteria, I will have to write a lot of if-elses to drop out specific arguments from the where clause .
The possible solution ?
I am actually new to the lambda expressions world but I believe we must be having a facility which would allow us to do something like below.
dbContext.Students.Where(processCriteria(searchCriteriaPOCO)).
Can you folks lead me to the proper direction ?. Thanks
Get a queryable and then keep adding where clauses to it. That way you only need to test each possible criteria the once and also only generate the number of where clauses that are absolutely needed.
IQueryable<Student> q = dbContext.Students.AsQueryable();
if (crit.name != null)
q = q.Where(c => c.name == crit.name);
if (crit.age != null)
q = q.Where(c => c.age== crit.age);
Let me start by saying that this answer uses the same basic idea as #PhilWright's answer. It just wraps it up in an extension method that applies this pattern for you, and allows you to have a syntax that reads nice.
public static class SearchExtensions
{
public static IQueryable<Student> Query(this SearchCriteria criteria, IQueryable<Student> studentQuery)
{
return studentQuery
.Match(criteria.name, (student) => student.name == criteria.name)
.Match(criteria.age, (student) => student.age == criteria.age)
.Match(criteria.talent, (student) => student.talent == criteria.talent);
// add expressions for other fields if needed.
}
private static IQueryable<Student> Match<T>(
this IQueryable<Student> studentQuery,
T criterionValue,
Expression<Func<Student, bool>> whereClause) where T : class
{
// only use the expression if the criterion value is non-null.
return criterionValue == null ? studentQuery : studentQuery.Where(whereClause);
}
}
You can then use it in your code like this:
var criteria = new SearchCriteria() {
name = "Alex",
talent = "Nosepicking"
};
var results = criteria.Query(dbContext.Students);
Maybe I'm missing something, as the code example is not the clearest I've seen, but for your specific example, I would think the following should be fine:
dbContext.Students.Where(c => (crit.name == null || crit.name == c.name) &&
(crit.age == null || crit.age == c.age) &&
(crit.talent == null || crit.talent == c.talent));
No need to chain a bunch of if statements.
For more complicated scenarios, you might prefer something like PredicateBuilder
You can use a pattern like this:
dbContext.Students.Where(c=>(crit.name == null || c.name ==crit.name) && ...)
A search criterion which is null will give a subexpression which is always true.
Any knows a quickest Ternary operation for this.
label1.Text = Cclass.TestMe()
.Where(t => t.GFName == (textBox1.Text == ""
? "GName"
: textBox1.Text))
.First()
.GFName == null ?
"Nothing" :
"Super";
I was trying to check if the List is empty return something. So the compiler will not throw a Exception or unhanded error.
The reason of this exception is First(). It will throw an exception if there's no row to be returned. Instead of that you can use FirstOrDefault() which will return the default value (NULL for all reference types) instead. But if you want to check if there any element inside your list which mathcing the condition, then you must use Any() extension method:
return Cclass.TestMe()
.Any(t => t.GFName == (textBox1.Text == "" ? "GName" : textBox1.Text)) ?
"Super" :
"Nothing";
By the way, it would be better to set text outside of your query:
var filteredText = textBox1.Text == "" ? "GName" : textBox1.Text;
return Cclass.TestMe().Any(t => t.GFName == filteredText) ?
"Super" :
"Nothing";
If I understand you right you want to return one value if the where clause returns something and another if not. That would be:
label1.Text = Cclass.TestMe()
.Any(t => t.GFName == (textBox1.Text == ""
? "GName"
: textBox1.Text)) ?
"Super" :
"Nothing";
If that's not what you want, then rearrange your code to use if statements to make it work, then make it better. Ugly working code is always better than elegant broken code.
I've got a method which can accept an optional int? value as a number of items to Take from a collection. I want to return all items if a null value is passed. Right now I have to duplicate my query to accomplish this
if(take == null)
{
x = db.WalkingDeadEps.Where(x => x.BicyclesCouldHaveSavedLives == true).ToList()
}
else
{
x = db.WalkingDeadEps.Where(x => x.BicyclesCouldHaveSavedLives == true).Take(take).ToList()
}
Is there a simpler way? Something like this?
.Take(take != null ? take : "all")
with Linq you have the option to store your query in variables. it will not be executed until you call ToList or equivalent methods on it.
var query = db.WalkingDeadEps.Where(x => x.BicyclesCouldHaveSavedLives == true);
x = take.HasValue ? query.Take(take.Value).ToList() : query.ToList();
var x = new {
Name = "qwe",
Options = someList.Select(x=>x.KEY).Select(x =>
new {
Title: someOtherList.FirstOrDefault(y => y.KEY == x) != null ?
someOtherList.FirstOrDefault(y => y.KEY == x).Title :
null
}
)
}).ToList();
I'm making a serializeable list of objects. Please have a look on how i fetch the Title property for each option.
My problem is that I'm fetching more properties than the title, and the conditional operator feels quite excessive for each property.
Is there any "better" way of writing this?
A simple solution would be to use the following:
Title= someOtherList.Where(y => y.KEY == x).Select(x => x.Title).FirstOrDefault()
That is doing the following:
From someOtherList, return those elements with Key equal to x.
From those elements, select the Title.
Return the first title - or null if there are none.
Canonically, the approach most similar to the original code is to use a statement lambda.
Options = someList.Select(x=>x.KEY).Select(x =>
{
var other = someOtherList.FirstOrDefault(y => y.KEY == x);
return new {
Title = other == null ? null : other.Title
};
})
You can call a method instead:
Options = someList.Select(x=>x.KEY).Select(x => CreateObject(x, someOtherList));
public YourObject(or dynamic) CreateObject(YourObject x, List<SomeOtherObject> someOtherList)
{
var other = someOtherList.FirstOrDefault(y => y.KEY == x);
return new
{
Title = (other == null ? null : other.Title),
Foo = (other == null ? null : other.Foo),
...
}
}
Or accomplish the same with the let keyword in a Linq query expression as #DarinDimitrov displays.