46

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,401
  • 13
  • 53
  • 87
  • 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
  • 41,265
  • 7
  • 89
  • 144
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
  • 50,967
  • 9
  • 90
  • 116
20

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();
    
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
  • 30,870
  • 7
  • 96
  • 158
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
  • 20,142
  • 17
  • 60
  • 81
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
  • 51,408
  • 11
  • 123
  • 146
  • 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,210
  • 21
  • 21
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
  • 1,543
  • 1
  • 13
  • 22
Ramy Samir
  • 11
  • 1