Best way to handle where clause in Lambda - asp.net-mvc

I have the following lambda for a simple search page using MVC:
Name and PostedName are strings.
Results.where(a=>a.Name.Contains(PostedName)).ToList();
Thanks great when PostedName has a value (excellent filter), but when it is empty, I get bupkas (empty list).
I would ideally like my where clause to be ignored when empty string.
How can this be done?
Something ideally shorthand without ifs and elses and whatifs.
Thanks!

You can dynamically add the WHERE clause. Keep in mind that you're just building an expression tree with these clauses and it's not actually executed until, in this case, you call .ToList(). So you can do something like this:
var filteredResults = Results;
if (!string.IsNullOrWhitespace(PostedName))
filteredResults = filteredResults.Where(a => a.Contains(PostedName));
filteredResults = filteredResults.ToList();
Depending on the types you may need to explicitly declare a type for filteredResults in order for that to compile.
If you want something a little more in-line, this may do the trick:
Results.Where(a => string.IsNullOrWhitespace(PostedName) || a.Contains(PostedName)).ToList();
I think it's less clear on the intent, though. The benefit of the first example is also that you can add more filters following the same structure, basically dynamically adding more WHERE clauses for other filter fields as needed.

David's answer is correct, but if you want a shortcut you can create an extension method to simplify usage example (untested by me).

I would suggest:
Results.Where(a => a.Name.Contains((PostedName ?? "").Trim())).ToList();
"ThisIsAString".Contains("") returns true.
In the case PostedName is null, it will be changed to "".
If there is leading and/or trailing blanks characters in PostedName, then they will be removed.

Related

How to add a copy of an object instead of reference to it

So - I am doping a loop in F# with some complex logic in it so I am using a System.Collections.Generic.List so I can add to it in the loop.
What I am finding though - is that when I add an item to the list - it still somehow has a reference to the variable so when I change the "currentPostCodeRange" variable, then all of the previous additions to the list are changed as well! is there a way I can assign a "copy" of the variable somehow so it doesn't reference every single item..?
let postcodeRanges: System.Collections.Generic.List<Postcode.PostcodeRange>
= new System.Collections.Generic.List<Postcode.PostcodeRange>()
let mutable currentPostCodeRange: Postcode.PostcodeRange = { RangeType = Postcode.RangeType.Normal; From="0001"; To="0001" }
Loop:
for postCode in 1 .. 9999 do
.....
if nextPostCodeisRural <> thisPostCodeisRural then
// this is the last one in this Range
currentPostCodeRange.To <- thisPostCodeString
postcodeRanges.Add(currentPostCodeRange)
.... etc, other logic
I think the easiest way to copy a record in F# is with a copy and update record expression. I strongly recommend against adding mutable objects to collections, though, precisely because it creates the aliasing problem you're seeing here. However, if you're determined to do it, you can add a copy like this:
postcodeRanges.Add({ currentPostCodeRange with To = currentPostCodeRange.To })
You have to include at least one field in the expression, so in this case, I've explicitly copied the To field, and implicitly copied the rest. It doesn't matter which one you pick.
Again, I strongly recommend against this sort of design. I think you're better off in the long run using a scan, or some other functional technique.

Find pages with tag

In a Umbraco 7 solution, i have a Tags Content picker on all pages. Pages can with this, set tags on each page.
I then want to get alle pages, within the intire site, that has, lets say tag 111 (id, not name).
I have tried with:
var ids = Model.MacroParameters["tags"]; //the tags to show
CurrentPage.AncestorOrSelf(1).Descendants().Where(x => ids.Contains(x.tags.ToString()));
But that gives me the error:
Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type
Whats the correct way?
Solved it with;
Umbraco.Content(rootId).Descendants().Where("tags.Contains(#0)", ids);
You have a few options, depending on whether you prefer a dynamic or strongly typed view model.
Strongly Typed API
Umbraco.TypedContentAtRoot().Descendants().Where(x => x.tags.Contains(ids));
Dynamic API
Umbraco.ContentAtRoot().Descendants().Where("tags.Contains(#0)", ids);
Please note that the Contains statement may give you inconsistent results, as the tags property seems to be returning a comma separated list. In that case you can try splitting the string or install the Core Property Value Converters package and get the tags as IEnumerable<IPublishedContent>
Always try to avoid using Descendants, especially on the root node.
To get the tags for a property:
ApplicationContext.Current.Services.TagService.GetTagsForProperty(Model.Content.Id, "propertyname")
To find content with a specific tag:
ApplicationContext.Current.Services.TagService.GetTaggedContentByTag("tag")

Get default value from Erlang record definition?

Is there an easy way to get a default value from an Erlang record definition? Suppose I have something like this:
-record(specialfield, {
raw = <<"default">> :: string()
}).
I would like to have some way to retrieve the default value of the raw field. Something like this would be very simple:
#specialfield.raw % => <<"default">>
This is not possible. I would need to instantiate a record in order to get the default value:
Afield = #specialfield{}
DefaultValue = Afeild#specialfield.raw
DefaultValue % => <<"default">>
Is there an easier way of doing this? I seems like there should be some way to retrieve the default value without having to create an instance of the record.
How about:
raw_default() -> <<"default">>.
-record(specialfield, { raw = raw_default() }).
And now you have a function with the default in it. This will be extremely fast since it is a function call to a constant value. If this is also too slow, enable inlining.
Constructing an empty record and accessing one field can be done on one line:
(#specialfield{})#specialfield.raw.
Take a look at erlang - records, search section "11.8".
There's not much special about records - they're just a tuple at runtime. So to get the field raw from the tuple of default values that is the internal representation of #specialfield{} you would use:
element(#specialfield.raw, #specialfield{}).
In this case, #specialfield.raw is the index of the value for raw in the #specialfield tuple. When you pass in specialfield that resolves to a tuple in the form {specialfield, <<"default">>}.

passing collections as parameters with neo4j

I have been using parameters to query node indexes as such (using the rest api in java)-
final QueryResult<Map<String,Object>> result = engine.query("start nd=node:name_index(name={src}) return nd.age as age", MapUtil.map("src", "Susan");
However I haven't been able to get this to work for a collection of nodes/names. I have been trying something along the lines of-
final QueryResult<Map<String,Object>> result = engine.query("start nd=node:name_index(name={src}) return nd.age as age", MapUtil.map("src", Arrays.asList("Susan","Brian", "Ian"));
But it refuses to compile. I as wondering if there is something wrong in my syntax or that parameters are not designed to work in this context.
The name= syntax in the start is meant to do an index lookup on a property. It won't do an IN lookup. The way you can do this sort of lookup is like this (note it depends on Apache's StringUtils):
List<String> names = Arrays.asList("Susan","Brian", "Ian");
String luceneQuery = "name:("+StringUtils.join(names, ",")+")";
engine.query("start nd=node:name_index({luceneQuery}) return nd.age as age", MapUtil.map("luceneQuery", luceneQuery));
Just a note, this is the "legacy" index way of doing things. In 2.0 they've introduced label-based indexes, which work entirely differently.
Thanks a lot; though it would still only return a non empty answer when I added a space after the comma in line 2. I used-
String luceneQuery = "name:("+StringUtils.join(names, ", ")+")";
and it returned the age of one person. When I tried this:
String luceneQuery = "fs:(fs:"+ StringUtils.join(names, " OR fs:")+")";
it gave me all three ages. However, I am still unsure about whether this query will be able to leverage the usual advantages of parameters , i.e. will the engine be able to reuse the query and execution path the next time around (this time we may want to query for 4 names instead of 3)

EntityDataSource Where Clause

I'm using a EntityDataSource with WhereParameters binded from DropDownLists. The Where Clause may be something like this: "it.applicationId = #applicationId" but in that DropDownList i've created a ListItem with Text="All" Value="".
Of course that when the value is "" i don't want to use that value on the query.
How can i do that?
Thank U All
It looks like there is no design time possibility to use parameters optionally.
Try hooking the Selecting event, like it is described in this question.
In your particular case you can get the selected value of the DropDownList (for example, using the FindControl method) and then simply either pass the value of the parameter, or use the query without a Where clause.
you should at first set the attribute "ConvertEmptyStringToNull" in your parameter to true
then type your where condition as follows
"#applicationId IS NULL OR it.applicationId = #applicationId"

Resources