1

I'm trying to understand how linq queries are executed.

As I know IQueryable queries are evaluated on server side together with filters and select and are executed only when ToList() or First() method is called.

However I'm having troubles understanding how the following query is evaluated. Is the "select new" evaluated on client side or on server side?

Is the Select(x=> new Note) triggers eager loading ?

IQueryable<Note> query = db.Notes
                           .Where(x => Id == someId)
                           .Select(c => new Note 
                                            {
                                                Title = x.Title
                                                Id = x.NoteId,
                                            });
Julie G
  • 41
  • 6
  • 2
    It's not really executed on the server side. On the client side it forms a corresponding SQL query and sends this. In your case the select statement defines the table columns to retrieve (Title and NoteId) and the object will be created on the client side. – Oliver Oct 13 '22 at 19:17
  • Like Oliver said everything is executed on client-side, `IQueryable` there simply delays the execution to when needed. So your projection (`Select`) will be taken onto account in generated SQL – paradise Oct 13 '22 at 19:47
  • 1
    See the duplicate(s). The key is that the *entire* expression (`query`) is translated into SQL. The SQL is executed by the database. But also see: https://learn.microsoft.com/en-us/ef/core/querying/client-eval – Gert Arnold Oct 13 '22 at 20:00
  • @GertArnold, why forced to close? just prepared explanation, which is not related to documentation which explains nothing. – Svyatoslav Danyliv Oct 13 '22 at 20:06
  • @paradise When the execution will happen ? – Julie G Oct 13 '22 at 20:59
  • @GertArnold I don t understand the following statement from documentation: "EF Core supports partial client evaluation in the top-level projection (essentially, the last call to Select())." – Julie G Oct 13 '22 at 21:05
  • @Svyatoslav Closing serves as building a system of signposts that point to more content. I thinks it's justified here. Maybe you can add your answer to the duplicate so it'll be visible to a larger audience (landing here and on the other question). – Gert Arnold Oct 13 '22 at 21:22
  • @JulieG If in the last `Select` there's code that can't be translated into SQL, EF will still translate everything before it into SQL, get that data from the database, and execute the last `Select` in memory (= client-side). This may happen if you do something like `Select(x => x.MapToDto(x))`, where `MapToDto` is a C# method. – Gert Arnold Oct 13 '22 at 21:26
  • @GertArnold understood. Shouldn' t I get translation exception for your described scenario?.. Can a part of query be executed in memory and still (query) be of type IQuerable? – Julie G Oct 13 '22 at 21:41
  • @GertArnold Also I was wondering when the mapping to object Note is happening. Thank you. – Julie G Oct 13 '22 at 21:46
  • @JulieG, create new question, this one is dead. I have prepared answer, but moderators won't read questions accurately. – Svyatoslav Danyliv Oct 14 '22 at 04:29
  • 1
    @SvyatoslavDanyliv Alright, reopened since you insisted. What kept you from answering the duplicate question? It should apply there as well. BTW, please don't stimulate people to ask a new question just because you don't like it to have been closed. If there's something you don't like, flag a question for moderator attention. Or bring it to [meta]. – Gert Arnold Oct 14 '22 at 06:48
  • @JulieG It will be executed when you'll access to `query` variable content. – paradise Oct 15 '22 at 10:07

1 Answers1

2

In your case Select new is a instruction how to map DbDataReader fields to Note object. Member access parts like x.Title is translated to reader instruction like dbReader.GetString(0).

Internally LINQ Translator generates SQL for retrieving data

SELECT 
    x.Title,
    x.NoteId
FROM Notes x
WHERE x.Id = @someId

And generates LambdaExpression (schematically)

(DbDataReader dr) => new Note
{
    Title = dr.GetString(0),
    Id = dr.GetInt32(1)
}

Then this LambdaExpression is compiled and cached. When LINQ Provider executes query via ToList(), ToArray(), etc, generated SQL is sent to the Database and starts process of enumerating DataReader. For each DataReader record applied above compiled lambda. It makes from IQueryable<Note> (server side) IEnumerable<Note> (client side).

This is VERY simple explanation what is done under hood.

Svyatoslav Danyliv
  • 21,911
  • 3
  • 16
  • 32
  • Thank you @SvyatoslavDanyliv. It's answering my question. If you don't mind, could you provide some resources which will help to broaden my knowledge. – Julie G Oct 14 '22 at 12:08
  • As I know there is no literature about that. Some articles. Everything I know from currently exists LINQ providers, like `EF Core`, `linq2db` (which I support) and [Relinq](https://github.com/re-motion/Relinq) based `NHibernate` or others. If you plan to create your own LINQ provider better to look closer at `Relinq` it simplifies things a lot. – Svyatoslav Danyliv Oct 14 '22 at 14:42