Why is Entity Framework generating the following nested SQL for Azure Mobile Services Table Controllers

Viewed 519

I'm trying to get to the bottom of an entity Framework issue when using it with a TableController

I've created the following setup.

  1. The basic TodoItem example provided with a new Mobile Web API which leverages EntityFramework, TableController & the default EntityDomainManager

    public class TodoItemController : TableController<TodoItem>
    {
        protected override void Initialize(HttpControllerContext controllerContext)
        {
            base.Initialize(controllerContext);
            context = new MobileServiceContext();
            context.Database.Log += LogToDebug;
            DomainManager = new EntityDomainManager<TodoItem>(context, Request);
        }
    
        public IQueryable<TodoItem> GetAllTodoItems()
        {
            var q = Query();
            return q;
        }
    
  2. A vanilla Web API 2 controller.

    public class TodoItemsWebController : ApiController
    {
    
        private MobileServiceContext db = new MobileServiceContext();
        public TodoItemsWebController()
        {
            db.Database.Log += LogToDebug;
        }
    
        public IQueryable<TodoItem> GetTodoItems()
        {
            return db.TodoItems;
        }
    

I've gone through the tablecontroller code with a fine tooth comb, digging into the Query method, which is just proxying the call via the DomainManager to add in the Where(_ => !_.IsDeleted) modification to the IQueryable

Yet the two queries produce VERY different SQL.

For the regular Web API Controller, you get the following SQL.

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Version] AS [Version], 
    [Extent1].[CreatedAt] AS [CreatedAt], 
    [Extent1].[UpdatedAt] AS [UpdatedAt], 
    [Extent1].[Deleted] AS [Deleted], 
    [Extent1].[Text] AS [Text], 
    [Extent1].[Complete] AS [Complete]
    FROM [dbo].[TodoItems] AS [Extent1]

But for the TableController, you get the following chunk of SQL which has a *Magic* Guid in the middle of it, and results in a Nested SQL statement. The performance of this goes to complete garbage when you start dealing with any of the ODATAv3 queries like $top, $skip, $filter and $expand.

SELECT TOP (51) 
    [Project1].[C1] AS [C1], 
    [Project1].[C2] AS [C2], 
    [Project1].[C3] AS [C3], 
    [Project1].[Complete] AS [Complete], 
    [Project1].[C4] AS [C4], 
    [Project1].[Text] AS [Text], 
    [Project1].[C5] AS [C5], 
    [Project1].[Deleted] AS [Deleted], 
    [Project1].[C6] AS [C6], 
    [Project1].[UpdatedAt] AS [UpdatedAt], 
    [Project1].[C7] AS [C7], 
    [Project1].[CreatedAt] AS [CreatedAt], 
    [Project1].[C8] AS [C8], 
    [Project1].[Version] AS [Version], 
    [Project1].[C9] AS [C9], 
    [Project1].[Id] AS [Id]
    FROM ( SELECT 
        [Extent1].[Id] AS [Id], 
        [Extent1].[Version] AS [Version], 
        [Extent1].[CreatedAt] AS [CreatedAt], 
        [Extent1].[UpdatedAt] AS [UpdatedAt], 
        [Extent1].[Deleted] AS [Deleted], 
        [Extent1].[Text] AS [Text], 
        [Extent1].[Complete] AS [Complete], 
        1 AS [C1], 
        N'804f84c6-7576-488a-af10-d7a6402da3bb' AS [C2], 
        N'Complete' AS [C3], 
        N'Text' AS [C4], 
        N'Deleted' AS [C5], 
        N'UpdatedAt' AS [C6], 
        N'CreatedAt' AS [C7], 
        N'Version' AS [C8], 
        N'Id' AS [C9]
        FROM [dbo].[TodoItems] AS [Extent1]
    )  AS [Project1]
    ORDER BY [Project1].[Id] ASC

You can see the results of both queries here. https://pastebin.com/tSACq6eg

So my questions are:

  • Why is the TableController generating the SQL in this way?

  • What is the *magic* guid in the middle of the query? (it will stay the same until I stop and restart the app so I don't know if it's session, client or DB context specific)

  • Where exactly in the pipeline is the TableController making these Modifications to the IQueryable? I assume it's done through some middleware step or an on executed attribute later in the request after the Query() method is called, but I cannot for the life of me find it.

2 Answers
Related