49

I am trying to get the first and last values in a list. The query operator First() is supported but Last() and LastOrDefault() give an error. Am I using the Last() operator incorrectly?

var purchaseBills = db.PurchaseBills.OrderBy(p => p.BillID);

if (purchaseBills.Count() >0)
{
    var firstBill = purchaseBills.First(); // This is supported

    // Attempt 1                    
    var lastBill = purchaseBills.Last(); // Not supported
    
    // Attempt 2
    var lastBill = purchaseBills.LastOrDefault(); // Not supported

    //Attempt 3
    var lastBill = purchaseBills.Reverse().First(); // Not supported
    
    textBoxPurchaseBillFrom.Text = firstBill.BillNo.ToString();
    textBoxPurchaseBillTo.Text = lastBill.BillNo.ToString();
}

Update:

--Errors--

Attempt 1: The query operator 'Last' is not supported.

Attempt 2: The query operator 'LastOrDefault' is not supported.

Attempt 3: The query operator 'Reverse' is not supported.

Community
  • 1
  • 1
Marshal
  • 6,551
  • 13
  • 55
  • 91
  • What is the error? What query provider are you using? – Daniel Rose Aug 31 '11 at 06:54
  • Possible duplicate of [LINQ To Entities does not recognize the method Last. Really?](http://stackoverflow.com/questions/7293639/linq-to-entities-does-not-recognize-the-method-last-really). This question was asked a month before the other question, but that question has better answers. – Tot Zam Mar 02 '17 at 16:46

8 Answers8

54
  • Instead of putting it into an own list by calling ToList() or ToArray() i would prefer to use AsEnumerable().
  • Additionally like the others you should try OrderByDescending()
  • Instead of Count() i would use Any().
Oliver
  • 43,366
  • 8
  • 94
  • 151
28

either you switch your OrderBy to

.OrderByDescending(p => p.BillID)

(and use first) or you do something like

purchaseBills.ToArray().Last()

if this is not to expensive.

Random Dev
  • 51,810
  • 9
  • 92
  • 119
21

Last is not supported by the back-end DB. You should try other techniques:

  1. Run your query using OrderByDescending so your requested item comes first.

  2. Code your LINQ query as usual, but enforce Linq2Sql to render it to a CLR collection and then you'll have free access to everything locally, including Last. Example:

    var bills = purchaseBills.ToList();
    var last = bills.Last();
    
  • While true that in most SQL dialects you `ORER BY ... DESC LIMIT 1`, Linq is just a SQL translation layer. Conceivably this translation could've been implemented but wasn't – CervEd Oct 27 '22 at 09:40
11

The problem is that there's no easy translation into SQL for Last or Reverse, so either convert it to something in memory (ToList, ToArray) if there aren't going to be too many records, or you could run the query a 2nd time, with OrderByDescending instead of OrderBy and use First.

George Duckett
  • 31,770
  • 9
  • 95
  • 162
  • "The problem is that there's no easy translation into SQL for Last or Reverse", there is. It's `ORDER BY ... DESC LIMIT 1`. The problem is `first` may be called on unordered queries, where the database offers no guarantee of order but ostensibly retrieves the first record in the clustered index. There's no `last` in this sense, because in SQL this can only be done with an explicit order. Imho, the LINQ implementation here is imprecise and an annoying source of runtime errors – CervEd Oct 27 '22 at 09:45
10

I try not to use LastOrDefault() because sometime it doesn't work or support. I'm sorting id by desc and then grab the first records.

.OrderByDescending(o=>o.id)
.FirstOrDefault(s => s.Name == Name)
Remi Guan
  • 21,506
  • 17
  • 64
  • 87
Lap Huynh
  • 101
  • 1
  • 3
4

It has something to do with the fact that the Last operator is trying to be sent to the SQL server which has no corresponding command. Once solution is to put a ToArray() or Tolist() at the end of your db call which makes that one line an explicit call to get the data (instead of lazing loading on each of the other lines).

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • Seems to be the first post to actually answer the question, which was "*Am I using the Last() operator incorrectly*" – mins May 13 '20 at 14:28
1

Yet another way get last element without orderbydescending and load all entities:

var lastBill = purchaseBills
    .Where(f => f.BillID == purchaseBills.Max(f2 => f2.BillID))
    .FirstOrDefault();
Stas Boyarincev
  • 3,690
  • 23
  • 23
1

You can convert your IEnumerable into a List using the ToList() method, which will ensure that all your attempts are successful, as shown:

var purchaseBills = db.PurchaseBills.OrderBy(p => p.BillID);

if (purchaseBills.Any())
{
  var firstBill = purchaseBills.First(); // This is supported

// Attempt 1                    
  var lastBill = purchaseBills.ToList().Last();

// Attempt 2
  var lastBill = purchaseBills.ToList().LastOrDefault(); 

//NoLogic
  var lastBill = purchaseBills.ToList().Reverse().First();

  textBoxPurchaseBillFrom.Text = firstBill.BillNo.ToString();
  textBoxPurchaseBillTo.Text = lastBill.BillNo.ToString();
}
AzuxirenLeadGuy
  • 2,470
  • 1
  • 16
  • 27
Ramy Samir
  • 11
  • 1