2

With EF Core 7.0, when I query data with basic pagination:

var data = (from item in _db.items
            where... // filtering
            orderby.... // ordering
            select item)


var dataToSend = await data.Skip(x).Take(Y).ToListAsync();

Everything works as expected.

However, when I try using Queryable.Take(x..y) "with the range parameter", for example:

var from = x;
var to = y;

var dataToSend = await data.Take(from..to).ToListAsync();

I receive an error that the LINQ expression could not be translated.

Why isn't this working?

Damascus
  • 145
  • 9
  • Check the most up votes answer here https://stackoverflow.com/questions/57872910/the-linq-expression-could-not-be-translated-and-will-be-evaluated-locally – MichaelMao Jan 07 '23 at 09:46
  • 1
    *Why isn't this working?* -- Just because there's no supported SQL translation for all LINQ-to-objects methods. – Gert Arnold Jan 07 '23 at 10:00
  • 2
    Yup, as @Gert (HNY!) said. The question is why Net Core BCL team is adding new methods to the interface if they are supported only in LINQ to Objects (which normally is not used with `IQueryable`), thus just opening additional confusion. Same for new types like `DateOnly` and `TimeOnly` - nice, but not supported even with their ADO.Net driver :( – Ivan Stoev Jan 07 '23 at 10:07
  • 2
    @Ivan (same to you!) Maybe because they're optimistic in what third-party query providers dare to implement. I only wish the [docs on supported LINQ methods](https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/supported-and-unsupported-linq-methods-linq-to-entities) would be kept up-to-date and were prominently present in the EF docs, preferably as a caption [here](https://learn.microsoft.com/en-us/ef/core/querying/). – Gert Arnold Jan 07 '23 at 10:42
  • 1
    Exactly! In documentation it is not possible to make a distinction between what can and can't be translated to SQL. As the `.Skip(x).Take(y)` is translatable I expected the .`Take(x..y)` to be translatable as well (both do the same with different syntax). A heads-up note in the documentation and maybe in the IDE will be very useful! – Damascus Jan 07 '23 at 10:54
  • @Damascus what about `source.Skip(x).Take(y - x + 1);` or use `SkipWhile` `TakeWhile` ? – Vivek Nuna Jan 07 '23 at 14:55
  • @viveknuna, the usual `.Skip(x).Take(y)` works. But my question was about the newer shorter syntax `.Take(Range)` which has no SQL translation support yet as mentioned in the accepted answer. I thought this would be supported by maybe dealing with `.Take(Range)` as a `.Skip(x).Take(y)` before translation. It may be not that simple; and the EF Core team certainly has more insight about why it isn't supported yet. – Damascus Jan 07 '23 at 15:12

2 Answers2

1

Why isn't this working?

.NET 6 has introduced several new LINQ methods (and overloads to existing ones) which require their support to be implemented in every LINQ provider otherwise they will not work correctly. ATM EF Core team is considering/working on supporting them - you can track this summary issue or this one, particularly covering Take(Range) (and ElementAt(Index)).

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
0

The Take method in LINQ expects an integer argument that represents the number of elements to take.

It also can accept a Range parameter, in the form of a Range object.

A small example:

using System;
using System.Linq;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            var result = numbers.AsQueryable().Take(2..4).ToList();

            Console.WriteLine(string.Join(", ", result));
        }
    }
}

Try adding the AsQueryable() before the Take() method.

The Take method in LINQ is equivalent to the SQL SELECT TOP clause, which also expects a single integer argument.