在我的表控制器中,我有:
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移动应用程序非常棒,但是多层抽象使得很难真正看到幕后发生的事情,因此更难调整。
非常感谢任何帮助。
答案 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();
}
答案 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;
}