【问题标题】:Azure Mobile Service Lookupasync load navigation propertiesAzure 移动服务 Lookupasync 加载导航属性
【发布时间】:2014-09-06 05:02:44
【问题描述】:

我在服务端有一个Place data_object,其中包含一个导航属性Roads

public class Place : EntityData
{
    ...
    public List<Road> Roads { get; set; }
}

现在在客户端,我想使用它的 id 获取一个 Place 对象,但是导航属性 Roads 不会加载。我可以添加任何参数或属性来使其工作吗?

我的代码:

var roadList = await App.MobileService.GetTable<Place>()
                .LookupAsync(placeId);

【问题讨论】:

    标签: azure azure-mobile-services


    【解决方案1】:

    由于在 EF 中加载导航属性需要在数据库中进行 JOIN 操作(这很昂贵),因此默认情况下不会加载它们,正如您所注意到的。如果要加载它们,则需要通过发送 $expand=&lt;propertyName&gt; 查询字符串参数从客户端请求。

    有两种实现方式:在服务器和客户端。如果您想在服务器中执行此操作,您可以实现一个操作过滤器,该过滤器将修改客户端请求并添加该查询字符串参数。您可以使用下面的过滤器来做到这一点:

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    class ExpandPropertyAttribute : ActionFilterAttribute
    {
        string propertyName;
    
        public ExpandPropertyAttribute(string propertyName)
        {
            this.propertyName = propertyName;
        }
    
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            base.OnActionExecuting(actionContext);
            var uriBuilder = new UriBuilder(actionContext.Request.RequestUri);
            var queryParams = uriBuilder.Query.TrimStart('?').Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries).ToList();
            int expandIndex = -1;
            for (var i = 0; i < queryParams.Count; i++)
            {
                if (queryParams[i].StartsWith("$expand", StringComparison.Ordinal))
                {
                    expandIndex = i;
                    break;
                }
            }
    
            if (expandIndex < 0)
            {
                queryParams.Add("$expand=" + this.propertyName);
            }
            else
            {
                queryParams[expandIndex] = queryParams[expandIndex] + "," + propertyName;
            }
    
            uriBuilder.Query = string.Join("&", queryParams);
            actionContext.Request.RequestUri = uriBuilder.Uri;
        }
    }
    

    然后你可以用那个属性装饰你的方法:

    [ExpandProperty("Roads")]
    public SingleItem<Place> GetPlace(string id) {
        return base.Lookup(id);
    }
    

    实现此目的的另一种方法是更改​​客户端代码以发送该标头。目前,采用额外查询字符串参数的LookupAsync(以及所有其他CRUD 操作)的重载不能用于添加$expand 参数(或任何其他$-* 参数),因此您需要为此使用处理程序。例如,这是一个这样的处理程序:

    class MyExpandPropertyHandler : DelegatingHandler
    {
        string tableName
        string propertyName;
    
        public MyExpandPropertyHandler(string tableName, string propertyName)
        {
            this.tableName = tableName;
            this.propertyName = propertyName;
        }
    
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (request.Method.Method == HttpMethod.Get.Method &&
                request.RequestUri.PathAndQuery.StartsWith("/tables/" + tableName, StringComparison.OrdinalIgnoreCase))
            {
                UriBuilder builder = new UriBuilder(request.RequestUri);
                string query = builder.Query;
                if (!query.Contains("$expand"))
                {
                    if (string.IsNullOrEmpty(query))
                    {
                        query = "";
                    }
                    else
                    {
                        query = query + "&";
                    }
    
                    query = query + "$expand=" + propertyName;
                    builder.Query = query.TrimStart('?');
                    request.RequestUri = builder.Uri;
                }
            }
    
            return await base.SendAsync(request, cancellationToken);
            return result;
        }
    }
    

    您可以通过创建MobileServiceClient 的新实例来使用处理程序:

    var expandedClient = new MobileServiceClient(
        App.MobileService.ApplicationUrl,
        App.MobileService.ApplicationKey,
        new MyExpandPropertyHandler("Place", "Roads"));
    var roadList = await App.MobileService.GetTable<Place>()
        .LookupAsync(placeId);
    

    【讨论】:

    • 感谢您对两种解决方案的详细回复!没想到可以自定义查询参数
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-21
    • 1970-01-01
    • 2016-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多