Azure移动服务Lookupasync加载导航属性

时间:2014-09-05 17:07:17

标签: azure azure-mobile-services

我在服务端有一个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);

1 个答案:

答案 0 :(得分:5)

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

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

[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);