How do we load related objects (Eager Loading) in Dot Net based Azure Mobile Service?

跟風遠走 提交于 2019-12-07 10:28:26

问题


If I have following model structure

public class QuestionItem: EntityData
{
    public string Content { get; set; }
    public bool IsAnswered { get; set; }
    public int NumberOfAnswers
    {
        //todo: make it computable
        get;
        set;
    }
    public UserItem By { get; set; }
    public string ById { get; set; }
    public string AtLocation { get; set; }
}

& parent entity as

public class UserItem:EntityData
{

    public string UserName { get; set; }

    public string Gender { get; set; }

    public string BaseLocation { get; set; }

    public int Age { get; set; }

    public int Points { get; set; }

}

this does generate the DB Tables with proper FK relationships. but when querying Question Items list, the QuestionItem.By property (reference object to UserItem table) is null.

generally this is achieved by using an .Include method on query level, but i am not able to find where exactly i should do this.

any help is appreciated.

Supreet


回答1:


As @JuneT mentioned, you need to send an $expand header from the client. The reason for that is that by default Entity Framework will not traverse object graphs, as this requires a join in the database and can have a negative performance impact if you don't need to do that.

Another alternative, which I mentioned in this blog post, is to use a filter in the server-side to add that header for you. For example, with this attribute below:

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

You can decorate your action to force the expansion of the related entity.

[ExpandProperty("By")]
public IQueryable<QuestionItem> GetAll() {
    return base.Query();
}



回答2:


Have the GetAllQuestionItems method look like this:

public IList<QuestionItem> GetAllQuestionItems()
{
    return context.QuestionItems.Include( "UserItem" ).ToList();
}

This is an alternative to the $expand hack. I discovered it while exploring Azure App Service mobile apps for myself. Your original idea to solve it simply by chaining a call to Include would make more sense to me, if it worked. Next, I'd like to figure out why it doesn't work.



来源:https://stackoverflow.com/questions/23333795/how-do-we-load-related-objects-eager-loading-in-dot-net-based-azure-mobile-ser

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!