替换TableController中的GET处理程序

时间:2018-01-09 00:53:55

标签: azure-mobile-services

在我的表控制器中,我有:

public IQueryable<MyTable> GetAllMyTable()

我想用我自己的替换:

[HttpGet, Route("tables/MyTable")]
public IEnumerable<MyTable> GetAllMyTable()

但是当我打电话给我时,我得到了这个回应:

HTTP/1.1 405 Method Not Allowed

不知何故,Web API路由没有达到我的方法。

为什么我这样做:原始方法产生低效的Entity Framework SQL查询,在我的本地测试环境中每次调用需要3秒。这是在SQL管理工作室中直接运行从SQL事件探查器捕获的查询。等效查询运行时间不到一秒。可怕。

更糟糕的是,效率低下的EF查询会消耗大量Azure SQL DTU,如果您想快速修复,则会诱使您提升Azure订阅级别。

Azure移动应用程序非常棒,但是多层抽象使得很难真正看到幕后发生的事情,因此更难调整。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

  

HTTP / 1.1 405方法不允许

根据我的理解,错误是显而易见的。您可以将GET HTTP谓词发送到端点tables/MyTable以检索数据。您需要通过提琴手检查您的移动应用后端请求。

  

Azure移动应用程序非常棒,但是多层抽象使得很难真正看到幕后发生的事情,因此更难调整。

对于公共表控制器,它看起来像这样:

public IQueryable<Message> GetAllMessage()
{
   return Query();
}

EntityDomainManager.cs下的Query()方法将如下所示:

IQueryable<TData> query = this.Context.Set<TData>();
if (!includeDeleted)
{
    query = query.Where(item => !item.Deleted);
}
return query;

如果它处理ODATA查询(例如$ top,$ skip,$ filter等),将生成嵌套SQL语句。我们可以修改操作以澄清它如下:

public IEnumerable<Message> GetAllMessage(ODataQueryOptions opt)
{
    var message = context.Set<Message>();
    var query2=opt.ApplyTo(message, new ODataQuerySettings());
    return query2.Cast<Message>().ToList();
}

enter image description here

答案 1 :(得分:0)

这是我绕过实体框架/ OData管道并使用直接SQL的原始尝试。 (如果支持Dapper,那会不会很好!)这个很好用,并且比EF产生的嵌套SQL更快。 OData的处理是hacky;我没有时间研究使用OData来提取UpdatedAt,skip和top的值。

我只对这种需要优化的方法使用这种方法。这是Azure移动应用客户端在执行拉取时调用的方法。

public IEnumerable<MyTable> GetAllMyTable()
    {
        var qryValues = HttpUtility.ParseQueryString(Request.RequestUri.Query);
        var updatedAtFilter = qryValues["$filter"];
        var skip = qryValues["$skip"];
        var top = qryValues["$top"];
        if (updatedAtFilter != null)
        {
            var r = new Regex(@"^.+datetimeoffset'(?<time>.+)'.+$", RegexOptions.None);
            var m = r.Match(updatedAtFilter);
            if (m.Success)
            {
                var updatedAt = m.Groups["time"].Value.Replace("T", " ");

                var sqlString = @"SELECT T0.*
                        FROM MyTable T0 
                        WHERE T0.UpdatedAt >= @UpdatedAt 
                        ORDER BY UpdatedAt, Id
                        OFFSET @Skip ROWS
                        FETCH NEXT @Top ROWS ONLY";
                var updatedAtParam = new SqlParameter("UpdatedAt", SqlDbType.DateTimeOffset);
                updatedAtParam.Value = updatedAt;
                var skipParam = new SqlParameter("Skip", SqlDbType.Int);
                skipParam.Value = int.Parse(skip);
                var topParam = new SqlParameter("Top", SqlDbType.Int);
                topParam.Value = int.Parse(top);
                var data = _context.Database.SqlQuery<MyTable>(sqlString, new object[] { updatedAtParam, skipParam, topParam }).AsEnumerable<MyTable>();

                return data;
            }
        }

        return null;
    }