0

I am not sure where shall I use Single and where shall I use SingleOrDefault. I understood the definition for both.

Single:

  1. It will always return one row.

  2. If no row found I will get an exception.

  3. If multiple rows found I will get an exception.

SingleOrDefault:

  1. It will always return one row, if not found then default value is returned (What is the meaning of this DEFAULT VALUE").

  2. If multiple rows then exception.

Question 1: What is the meaning of "It will return default value"

Question 2: When to use Single and when to use SingleOrDefault.

I have a delete function where I have below code:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int resumeId)
{
    var r = _context
        .Resumes
        .Where(c => c.ResumeId == resumeId).SingleOrDefault();
    _context.Resumes.Remove(r);
    _context.SaveChanges();

    return RedirectToAction("ResumeCenter");
}

I just blindly put SingleOrDefault everywhere (where I ATMOST expect one value), Please tell me a real world scenario when I should use "Single" and where I should use "SingleOrDefault".

Kevin
  • 93
  • 2
  • 12
Unbreakable
  • 7,776
  • 24
  • 90
  • 171
  • The 'default' is a `null` because its a reference type, so if there are no matching records, the value of `r` will be `null` (and no exception will be thrown) –  Sep 07 '17 at 05:05
  • So, al DBSet's are referece types? – Unbreakable Sep 07 '17 at 05:09
  • `public DbSet Resumes { get; set; }` – Unbreakable Sep 07 '17 at 05:09
  • Can you kindly tell me when I should use them. Like in current scenario for "delete" do I need to use singleorDefault or not. I mean I just use `singleordefault` everywhere. :-| – Unbreakable Sep 07 '17 at 05:10
  • No, I mean the object that your query returns is a reference type (i.e. and instance of your `Resume` class) –  Sep 07 '17 at 05:10
  • It depends on the behavior you want. If you want an exception when nothing is found, use `Single`. If you want a null (for reference types), use `SingleOrDefault`. – BJ Myers Sep 07 '17 at 05:12
  • Understood, query will not return a DBSet. It will return an instance of Resume. got it. :) – Unbreakable Sep 07 '17 at 05:12
  • @BJMyers: If you were to write a delete HTTPPOST for a resource, what will you do? Just curious.. – Unbreakable Sep 07 '17 at 05:14
  • That really depends on other issues. For example, there may be a chance 2 users will execute that method at the same time. The record will be deleted by the first user, so using `.Single()` would throw an exception for the 2nd user. Using `. SingleOrDefault()` means you would not get that exception (and you only delete from the db if its not `null`) –  Sep 07 '17 at 05:15

5 Answers5

5

As you said - Single() will raise an exception if no row found. SingleOrDefault() will instead return the default value (null for reference types, 0 for ints, \0 for chars etc`).

Use Single() in one of two cases:

  1. When not getting a row is something that should not happen, and if it does, it means something is wrong.
  2. When you are dealing with value types (ints, chars, etc'), and the default value might be a valid value in your values system (for instance, if you are getting 0 for an int but can't tell if it's because you got no row back or it's a valid value.

Use SingleOrDefault() for any other case. If the row is not found, you'll need to compare the value you get to it's default value.

For further reading, here is a link to Microsoft page on the default value expression.

Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
2

It's almost (but not quite) a question of style. Which do you prefer?

Single:

try
{
    var x = someEnumerable.Single();
}
catch (InvalidOperationException)
{
    //Did not contain exactly one record
}

SingleOrDefault:

var y = someEnumerable.SingleOrDefault();
if (y == null)
{
    //Did not contain exactly one record
}

The exception-based approach is a little more coding, but it is nice because exceptions can be allowed to bubble up. That being said, I usually use the XXXOrDefault variants to avoid stack unwind, which can be poor for performance. As a rule you should avoid throwing exceptions when behaviors are expected.

P.S. The "default" for any type can be obtained by using the keyword default(type). For integers it is zero, for dates it is MinValue, for reference types it is null, etc.

P.P.S. In your example I would use Single and allow an exception to be thrown if the row is missing or there is more than one. Otherwise you may end up passing null to the subsequent Remove method. While that would fail too, it'd fail a line later than it ought to, resulting in a deceptive stack trace and making troubleshooting a little trickier.

OTOH, with small changes, you could make either one work:

public ActionResult Delete(int resumeId)
{
    var r = _context
        .Resumes
        .Where(c => c.ResumeId == resumeId).SingleOrDefault();
    if (r == null)
    {
        return RedirectToAction("ErrorPage");
    }
    else
    {
        _context.Resumes.Remove(r);
        _context.SaveChanges();
        return RedirectToAction("ResumeCenter");
    }
}

Or

public ActionResult Delete(int resumeId)
{
    var r = _context
        .Resumes
        .Where(c => c.ResumeId == resumeId).Single();  //Error will bounce up to Application_Error or other global handler
    _context.Resumes.Remove(r);
    _context.SaveChanges();

    return RedirectToAction("ResumeCenter");
}
John Wu
  • 50,556
  • 8
  • 44
  • 80
  • 4
    It's **not** a question of style at all. Exceptions should be used only to indicate an *exceptional* state. – Zohar Peled Sep 07 '17 at 05:17
  • Apart from throwing and catching exceptions being expensive, throwing an exception in the case where another user might have deleted the same record in the mean time is probably not desirable. –  Sep 07 '17 at 05:21
0

When you know that there has to be a value for some thing in the database, use Single() because you would want to get an exception if the "very expected value" in the database does not exist. Data like EmployeeName for a particular employee code.

Use SingleOrDefault() when you know employee is a temporary employee and his department may not show up in the main database. But if value for department exists, it should be only one value. He will not be working for multiple departments at once.

http://www.c-sharpcorner.com/blogs/singleordefault-vs-firstordefault-in-linq-query1

Single() - Atleast one value is expected in data store, and you would want it. You want to know if there is no value or multiple values. In that case, you get an exception and check.

SingleOrDefault() - Give one record with the default value if it does not exist. It does not matter whether on not anything is available for the record. But it should not be multiple records.

Amit Kumar Singh
  • 4,393
  • 2
  • 9
  • 22
0

as the function name suggest you when you say

list.single();

then that means

"I want the single record from the list" and hence you get the single record (the 1st one)"

and when yo say

list.SingleOrDefault();

then that means

"I wan the single record and if the record dosen't exist the i would like to have the default value of the object"

its your approch completely you can also go for

FirstOrDefault(); 

just like single or default

RAHUL S R
  • 1,569
  • 1
  • 11
  • 20
0

Single : It returns a single specific element from a collection of elements if element match found. An exception is thrown, if none or more than one match found for that element in the collection.

SingleOrDefault: It returns a single specific element from a collection of elements if element match found. An exception is thrown, if more than one match found for that element in the collection. A default value is returned, if no match is found for that element in the collection.

Irakli Gabisonia
  • 806
  • 8
  • 19