问题
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