How can I make LINQ Lambda expressions fail gracefully like XPath? - linq

More a general question, but how can I write LINQ Lambda expressions such that they will return a default string or simply an empty string if the LINQ expression fails or returns nothing. In XSLT XPath if a match fails then one just got nothing, and the application did not crash whereas in LINQ one seems to get exceptions.
I use First() and have tried FirstOrDefault().
So example queries may be:
Customers.First(c=>c.id==CustId).Tasks.ToList();
or
Customers.Where(c=>c.id==CustId).ToList();
or
Model.myCustomers.Where(c=>c.id==CustId);
etc.
Whatever the query, if it returns no records or null, then is there a general approach to ensure the query fails gracefully?
Thanks.

There isn't anything elegant built into C# for propagating nulls when you access properties. You could create your own extension methods:
public static class Extensions
{
public static TValue SafeGet<TObject, TValue>(
this TObject obj,
Func<TObject, TValue> propertyAccessor)
{
return obj == null ? default(TValue) : propertyAccessor(obj);
}
public static IEnumerable<T> OrEmpty<T>(this IEnumerable<T> collection)
{
return collection ?? Enumerable.Empty<T>();
}
}
Used like this:
Customers.FirstOrDefault(c => c.id==CustId).SafeGet(c => c.Tasks).OrEmpty().ToList();

Customers.First(c=>c.id==CustId) will crash if there is no matching record.
There are few ways you can try to find it, if you use FirstOrDefault that'll return NULL if no match is found and you can check for NULL.
Or, you can use the .Any syntax which checks if you have any record and returns boolean.

The only query I would expect to throw an exception would be the first one (assuming that Customers is a valid collection and not null itself):
Customers.First(c=>c.id==CustId).Tasks.ToList();
This will throw an exception if there is no customer with an id of CustId (you have some casing issues with your property and variable names).
If you don't wish to throw an exception on no match, then use FirstOrDefault as you mention, and do a null check, e.g:
var customer = Customers.FirstOrDefault(c => c.id == CustId);
if (customer == null)
{
// deal with no match
return;
}
var taskList = customer.Tasks.ToList();

Related

SPeL - set a value of an object which should be in an empty list

I have the following SPel expression:
custData.address[0].postcode
The custData is an existing object but the address is an empty list. It is an existing object but it is empty. When I try to set a the post code on this path then I got the
org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'postcode' cannot be found on null
What I'd need that a new address object will be put to the list and set its postcode attribute.
Is it something that can be done in the SPel expression?
Thanks,
V.
So this basically is a NullPointerException. You need to make sure the object from which you are trying to get a field value exists. SPeL has the special operator '?' to check if the object has value, though I'm not sure if it works for an array, but definitely worth a try. In general expression where some object might be null looks like this:
object?.anotherObject?.field
This makes sure that "object" is not null and if it has value gets "anotherObject" and check if it's not null either, and then gets "field". So try something like this:
custData.address[0]?.postcode
Eventually I ended up using a custom function in spel expression.
#addIfNecessary(custData.address, 0, "uk.co.acme.AddressType").postcode
The user defined function is
import org.springframework.util.ReflectionUtils;
import java.util.List;
public class CustomFunc {
public static Object addIfNecessary(List<Object> list, Integer index, String className) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
Object o = null;
if (list != null) {
if (list.size() <= index || list.get(index) == null) {
list.set(index, Class.forName(className).newInstance());
}
o = list.get(index);
}
return o;
}
}
It is neither nice nor elegant but it works.
Please let me know if you have a more elegant one!

How to extend LINQ select method in my own way

The following statement works fine if the source is not null:
Filters.Selection
.Select(o => new GetInputItem() { ItemID = o.ItemId })
It bombs if "Filters.Selection" is null (obviously). Is there any possible way to write my own extension method which returns null if the source is null or else execute the "Select" func, if the source is not null.
Say, something like the following:
var s = Filters.Selection
.MyOwnSelect(o => new GetInputItem() { ItemID = o.ItemId })
"s" would be null if "Filters.Selection" is null, or else, "s" would contain the evaluated "func" using LINQ Select.
This is only to learn more about LINQ extensions/customizations.
thanks.
You could do this:
public static IEnumerable<U> SelectOrNull<T,U>(this IEnumerable<T> seq, Func<T,U> map)
{
if (seq == null)
return Enumerable.Empty<U>(); // Or return null, though this will play nicely with other operations
return seq.Select(map);
}
Yes have a look at the Enumerable and Queryable classes in the framework, they implement the standard query operators.
You would need to implement a similar class with the same Select extension methods matching the same signatures, then if the source is null exit early, you should return an empty sequence.
Assuming you're talking about LINQ to Objects, absolutely:
public static class NullSafeLinq
{
public static IEnumerable<TResult> NullSafeSelect<TSource, TResult>
(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
// We don't intend to be safe against null projections...
if (selector == null)
{
throw new ArgumentNullException("selector");
}
return source == null ? null : source.Select(selector);
}
}
You may also want to read my Edulinq blog post series to learn more about how LINQ to Objects works.

Use LINQ to select Single from nested collections

I have two classes - MyBaseClass and BaseClassContainer - that are declared like such:
public class MyBaseClass
{
private Guid id;
public Guid ID
{
if (id == Guid.Empty)
{
id = Guid.NewGuid();
}
return id;
}
//...Other Properties omitted for brevity
}
and
public class BaseClassContainer : INotifyPropertyChanged
{
private ObservableCollection<MyBaseClass> baseClasses;
public ObservableCollection<MyBaseClass> BaseClasses
{
//...Omitted for brevity...
}
}
Then in my code I have an ObservableCollection of type BaseClassContainer (BaseClassContainerCollection). What I'm trying to figure out is how can I use LINQ to select a single BaseClassContainer from the ObservableCollection where one of its MyBaseClass.ID matches a specific Guid. The reason I'm using the Single() method is because I know they're all going to be unique.
I've tried the following but it doesn't work:
var result = BaseClassContainerCollection.Single(container => container.BaseClasses.Single(baseClass => baseClass.ID == specificGuid));
I get an error saying: Cannot implicitly convert type 'MyBaseClass' to 'bool'. What am I missing?
Lets break apart your query:
BaseClassContainerCollection.Single(yourPredicate);
Single, as it is used here, basically says "filter BaseClassContainerCollection on this predicate" (a "filter" function that evaluates to true or false for whether or not to include it in the results). Instead of a function that returns true/false, you're saying you want it to evaluate to a MyBaseClass, which doesn't make sense. Your inner call to Single makes sense, because x => x.Id == guid is a function that returns true/false and filters to only those elements that meet the criteria (then states that you know there will only be one of them in the results or else throw an exception).
What you want to do is Select the single MyBaseClass result from the inner query, then call Single on the result (without a predicate) since you know the result should only have one item returned. I believe you're looking for:
BaseClassContainerCollection.Select(container => container.BaseClasses.Single(baseClass => baseClass.ID == specificGuid)).Single();

Linq throwing exception when Null is returned to a string - attribute on a class?

I have a Linq query which I am selecting into a string, of course a string can contain null!
So is there a way I can throw an exception within my Linq query, if I detect a null?
Can I decorate my class with an attribute that won't let it allow null?
I would like to wrap my Linq query in a try catch, and as soon as a null is detected then it would enter the catch, and I can handle it.
Edit
Here's my Linq query, it's quite simple currently. I am going to extend it, but this shows the basic shape:
var localText = from t in items select new Items { item = t.name }
Basically item is set to t.name, t.name is a string so it could be empty / null is this perfectly legal as its a string and strings can hold NULL.
So if it returns NULL then I need to throw an exception. Actually it would be handy to be able to throw an exception is NULL or empty.
I seemed to remember some kind of Attributes that can be set on top of properties that says "Don't accept null" etc.?
Edit
I think I found it: http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.requiredattribute.aspx
This doesn't allow null or strings so I presume it throws an exception, I have used this with MVC but I am not sure if I can use it with a standard class.
As a string being null isn't particularly exceptional, you could do something like:
var items = myStrings.Where(s => !string.IsNullOrEmpty(s)).Select(s => new Item(s));
UPDATE
If you are reading this data from an XML file, then you should look into LINQ to XML, and also use XSD to validate the XML file rather than throwing exceptions on elements or attributes that don't contain strings.
You could try intentionally generating a NullReferenceException:
try
{
//Doesn't change the output, but throws if that string is null.
myStrings.Select(s=>s.ToString());
}
catch(NullReferenceException ex)
{
...
}
You could also create an extension method you could tack on to a String that would throw if null:
public static void ThrowIfNull(this string s, Exception ex)
{
if(s == null) throw ex;
}
...
myString.ThrowIfNull(new NullReferenceException());
Why do you want to throw an exception in this case? This sounds like throwing the baby out with the bath water for something that should not happen in the first place.
If you just want to detect that there are null/empty items:
int nullCount= items.Count( x=> string.IsNullOrEmpty(x.name));
If you want to filter them out:
var localText = from t in items where !string.IsNullOrEmpty(t.name) select new Items { item = t.name };

Use of "Single" in Dynamic Linq

I am trying to convert a Linq query that I have working in Linq to be able to work in dynamic linq (using System.Linq.Dynamic) because I want a user to be able to form their own queries and this query string would be added onto other query strings at runtime.
I have a query:
db.incidents.Where(a => a.incidentLocations.Single().location.street.Contains(location);
and I have tried to convert it to the following dynamic linq string:
query =
string.Concat("incidentLocations.Single().location.street.Contains(\"", location, "\")");
db.incidents.Where(query);
Where location is a string that includes search text.
I have managed to convert all my other queries to dynamic linq but this one i am struggling with the exception error:
"No applicable aggregate method 'Single' exists"
I understand that dynamic linq does not support all extension methods, could someone possibly tell me how I could get round this problem.
Get the source of Linq.Dynamic, copy paste the Where method, change the signature and the string with the function name inside the method and you're good to go. I did it to add Single First etc, I can't copy it here because I'm not on my dev machine but I'll do it later if necessary ;)
EDIT: here's the Single method if you decide to use it:
public static object Single(this IQueryable source)
{
if (source == null) throw new ArgumentNullException("source");
return source.Provider.Execute(
Expression.Call(
typeof(Queryable), "Single",
new Type[] { source.ElementType },
source.Expression));
}
Sorry to digg up a very old thread, but I thought I could add somevaluable information!
I had to do this for First()/FirstOrDefault() with Linq to Entities instead of your Linq to SQL and I can confirm #Guillaume86 's solution sure works!
Here's how I modified MicrosoftDynamic.sql:
I added this inside the static DynamicQueryable class:
public static object FirstOrDefault(this IQueryable source)
{
if (source == null) throw new ArgumentNullException("source");
return source.Provider.Execute(
Expression.Call(
typeof(Queryable), "FirstOrDefault ",
new Type[] { source.ElementType },
source.Expression));
}
I also modified interface IEnumerableSignatures as
void FirstOrDefault();
(I used FirstOrDefault because First() isn't supported when it's not the last call in linq to entities)
You can repeat this for any supported function :)

Resources