13

In a LINQ to entities expression like this:

var vote = (from vote in db.Vote where
    vote.Voter.Id == user.Id
    select v).FirstOrDefault();

How do you add a DefaultIfEmpty value so that when there's no vote I'd get a default value?

Stuart Helwig
  • 9,318
  • 8
  • 51
  • 67
Pablo Fernandez
  • 279,434
  • 135
  • 377
  • 622

5 Answers5

19

Another approach, if Vote is a reference type and thus uses null as its default value, would be to use the null coalescing operator:

var vote = (db.Vote
   .Where(v => v.Voter.Id == user.Id)
   .FirstOrDefault()) ?? defaultVote;
Robert Rossney
  • 94,622
  • 24
  • 146
  • 218
5

Add your own extension method. For instance:

public static class Extension
{
    public static T FirstOrDefault(this IEnumerable<T> sequence, T defaultValue)
    { 
        return sequence.Any() ? sequence.First() : defaultValue;
    }
}

With that class in scope, you can say:

var vote = (from vote in db.Vote where
    vote.Voter.Id == user.Id
    select v).FirstOrDefault(yourDefaultValue);

Of course, your method can also have an overload that returns default(T), if that was what you where looking for. There is already defined a DefaultIfEmpty extension method in the built-in Extension class, so I named the method in the example "FirstOrDefault", which seems like a better fit.

driis
  • 161,458
  • 45
  • 265
  • 341
4

Just add the default value before getting the first element.

var vote = db.Vote
    .Where(v => v.Voter.Id == user.Id)
    .DefaultIfEmpty(defaultVote)
    .First();

Note that you can now safely use First() instead of FirstOrDefault().

UPDATE

LINQ to Entity does not recognize the DefaultIfEmpty() extension method. But you can just use the null coalescing operator.

var vote = db.Vote.FirstOrDefault(v => v.Voter.Id == user.Id) ?? defaultVote;
Daniel Brückner
  • 59,031
  • 16
  • 99
  • 143
  • 1
    If when adding a default you can use First, why does FirstOrDefault exists at all? – Pablo Fernandez Jul 14 '09 at 18:27
  • Many of the LINQ operators are somewhat redundant - sequence.Any() can be rewritten as sequence.Count() > 0. You can use sequence.Where(item => Condition(item)).First() or sequence.First(item => Condition(item)). You can use joins or nested queries. When writing code you can use for, do, and while loops. You can even use goto. Usually there is not just one way to achieve a given goal. – Daniel Brückner Jul 14 '09 at 18:33
  • 3
    Note that seq.Count() (for objects that don't implement ICollection) will enumerate the full sequence while seq.Any() will return as soon as an element is found. Similar, but different. :) – dahlbyk Jul 15 '09 at 03:43
  • Of course, the count solution might be much slower. I just wanted to point out that there are usually quite a few ways to achieve a goal. – Daniel Brückner Jul 15 '09 at 08:50
  • `First()` will throw an exception if the sequence is empty. `FirstOrDefault()` will not, so you can control the behavior. – Suncat2000 Aug 17 '17 at 12:57
1

I ended up going for a very simple approach which was recommended by an answer here that was latter erased:

var vote = (from vote in db.Vote 
            where vote.Voter.Id == user.Id
            select v).FirstOrDefault();
if (vote == null) {
    vote = new Vote() { .... };
    db.AddToVoteSet(vote);
}
Pablo Fernandez
  • 279,434
  • 135
  • 377
  • 622
  • 1
    FYI, this did not satisfy your original question. You explicitly asked for it to return a default value, not to create a new value if it didn't already exist. (This is fine code, just doesn't do what you asked.) – BenSwayne Jun 11 '12 at 20:13
0

For some reason if I turn the resultset into a List, the Defaultifempty() works I don't know if I've inadvertantly crossed over into Linq area.

var results = (from u in rv.tbl_user
                        .Include("tbl_pics")
                        .Include("tbl_area")
                        .Include("tbl_province")
                        .ToList()
                        where u.tbl_province.idtbl_Province == prov
                       select new { u.firstName, u.cellNumber, u.tbl_area.Area, u.ID, u.tbl_province.Province_desc,
                                    pic = (from p3 in u.tbl_pics
                                           where p3.tbl_user.ID == u.ID
                                           select p3.pic_path).DefaultIfEmpty("defaultpic.jpg").First()
                                               }).ToList();
Rand
  • 39
  • 2
  • 6