Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SingleOrDefault() throws an exception on more than one element

Tags:

I'm getting an exception whenever I fetch like this

Feature f = o.Features.SingleOrDefault(e => e.LinkName == PageLink);

because this can return one or more than one element. What is the alternative approach that I can use to solve this issue?

like image 523
Fraz Sundal Avatar asked Jul 06 '10 09:07

Fraz Sundal


People also ask

What exception does SingleOrDefault throw?

SingleOrDefault<TSource>(IEnumerable<TSource>) Returns the only element of a sequence, or a default value if the sequence is empty; this method throws an exception if there is more than one element in the sequence.

What are the statements true about SingleOrDefault () method in Ling?

SingleOrDefault() will return default value of a data type of generic collection if there is no elements in a colection or for the specified condition. SingleOrDefault() will throw an exception if there is more than one elements in a colection or for the specified condition.

What is the difference between FirstOrDefault () and SingleOrDefault () extension method in Linq?

When you want a default value is returned if the result set contains no record, use SingleOrDefault. When you always want one record no matter what the result set contains, use First or FirstOrDefault. When you want a default value if the result set contains no record, use FirstOrDefault.

What is difference between first () and FirstOrDefault ()?

The major difference between First() and FirstOrDefault() is First will throw an exception when there are no results and FirstOrDefault won't. In fact, FirstOrDefault will simply return the null value (reference types) or the default value of the value type.


2 Answers

Single and SingleOrDefault are designed to throw if more that one match exists in the sequence. A consequence of this is that the entire sequence must be iterated prior to completion. It does not sound like this is what you want. Try FirstOrDefault instead:

Feature f = o.Features
    .FirstOrDefault(e => e.vcr_LinkName == PageLink && e.bit_Activate == true);

This will (generally) perform better because it completes as soon as a match is found.

Of course, if you actually want to retain more than one element, a Where clause would be more appropriate:

IEnumerable<Feature> fs = o.Features
    .Where(e => e.vcr_LinkName == PageLink && e.bit_Activate == true);
like image 192
spender Avatar answered Oct 18 '22 15:10

spender


Alternatively, if you only want the item when there is exactly one match and do not want to throw when there are more than one, this can be easily accomplished. I've created an extension method for this in my project:

public static class QueryableExtensions
{
    public static TSource SingleWhenOnly<TSource>(this IQueryable<TSource> source)
    {
        if (source == null)
            throw new ArgumentNullException("source");

        var results = source.Take(2).ToArray();

        return results.Length == 1 ? results[0] : default(TSource);
    }

    public static TSource SingleWhenOnly<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        if (predicate == null)
            throw new ArgumentNullException("predicate");

        var results = source.Where(predicate).Take(2).ToArray();

        return results.Length == 1 ? results[0] : default(TSource);
    }
}
like image 26
Pieter van Ginkel Avatar answered Oct 18 '22 13:10

Pieter van Ginkel