16

我試圖用TableController爲什麼實體框架生成Azure的移動服務表控制器

我創建了以下設置使用時才能到實體框架問題的底部以下嵌套的SQL。

  1. 提供一個新的移動網絡API它利用的EntityFramework,TableController &默認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. 香草網頁API 2控制器的基本的TodoItem例子。

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

我已經通過tablecontroller代碼用細齒梳去,挖到Query方法,它只是進行代理通過DomainManager調用在Where(_ => !_.IsDeleted)修改添加到IQueryable

然而,這兩個查詢產生了非常不同的SQL。

對於常規Web API控制器,您將獲得以下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] 

但對於TableController,你得到的SQL以下塊具有*魔法*的Guid在它的中間,並導致一個嵌套的SQL語句。當你開始處理像$ top,$ skip,$ filter和$ expand這樣的任何ODATAv3查詢時,這會導致完成垃圾。

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 

這裏你可以看到這兩個查詢的結果。 https://pastebin.com/tSACq6eg

所以我的問題是:

  • 爲什麼TableController產生這樣的SQL?

  • 什麼是* magic * guid在查詢中? (它會保持不變,直到我停止並重新啓動應用程序,所以我不知道這是否是會話,客戶或特定DB上下文)

  • 確切位置在哪裏的管道是使這些修改到IQueryable的TableController?我假定在調用Query()方法之後,它通過一些中間件步驟或稍後在請求中執行的屬性完成,但我不能在我的生活中找到它。

+0

我想這與移動服務器SDK實現Odata查詢有關。我發現如果我們使用var items = Query()。ToList(),sql查詢就像web api一樣。但我們無法使用Odata查詢。 –

+0

這並不是一個真正的選擇,因爲客戶的消費者會依賴Odata $ vars。例如在初始加載時,它將使用'$ top'&'$ skip'通過API調用來執行初始數據庫同步。 –

+0

這是因爲EntityDomainManager會爲每個行下載並保留字段值以進行併發檢查。而Guid是一種來自https://github.com/Azure/azure-mobile-apps-net-server/blob/master/src/Microsoft.Azure.Mobile.Server.Entity/EntityDomainManager.cs的ETAG –

回答

5

根據你的描述,我做了一些研究,發現Azure的移動服務器SDK使用下面的代碼行TableControllerConfigProvider.cs下添加額外的查詢相關的過濾器與QueryableAttribute同樣的動作用於啓用控制器操作來支持OData查詢參數。

controllerSettings.Services.Add(typeof(IFilterProvider), new TableFilterProvider()); 

注意:你的行動已經被執行之後額外的過濾器將被執行並返回IQueryable

你可以檢查EnableQueryAttribute.cs,發現OnActionExecuted會調用ExecuteQuery方法,最終調用ODataQueryOptions.ApplyTo用於應用的OData查詢選項($過濾器,$排序依據,$頂部,$跳過,和$ inlinecount等)給定的IQueryable

根據我的理解,嵌套SQL語句由OData組件生成。調用ODataQueryOptions.ApplyTo後,您的IQueryable已被修改,並且相關的sql語句也已被修改。我做了一些測試,我的正常的Web API控制器如下,你可以參考一下吧:

請求:

Get http://localhost:58971/api/todoitem?$top=2&$select=Text,Id,Version 

之前將OData的查詢選項:

enter image description here

應用OData查詢選項後:

enter image description here