OData / WebApi

OData Web API: A server library built upon ODataLib and WebApi
https://docs.microsoft.com/odata
Other
856 stars 473 forks source link

Dynamically generating Entity Framework Include based on $expand? #1117

Open NetTecture opened 6 years ago

NetTecture commented 6 years ago

This is a documentation request.

I can not wrap my head around this and do not find any relevant documentation.

Depending on the $expand clause, I must generate a set of dynamic .Include clauses for Entity Framework.

Is there any current example on how to analyze the $expand statement as I can get from the ODataQueryOptions?

I manage to get to this:

       var se = queryOptions.SelectExpand;
        foreach (var selectedItem in se.SelectExpandClause.SelectedItems) {
            if (selectedItem.GetType() == typeof(ExpandedNavigationSelectItem)) {
                ExpandedNavigationSelectItem navigationProperty = (ExpandedNavigationSelectItem)selectedItem;

but I am unable to get the last cast working. Examples seem to be outdated. This is the set of includes:

using System.Data.Entity; using System.Linq; using System.Web.OData; using System.Web.OData.Routing; using System.Web.OData.Query;

using Microsoft.Data.OData.Query; using Microsoft.Data.OData.Query.SemanticAst;

Part of the problem may well be that I am using AutoMapper ProjectTo - but this just is needed to hide the entities from the API level and allow efficient querying. Anyone has an example how to get the necessary expand paths (as strings)?

mtroth-microsoft commented 6 years ago

Did you try posting your question on stack overflow? Git hub issues is more likely to get focus in the context of a PR you are submitting to address a problem or add a feature. Questions are generally best circulating through the stack overflow community.

PabloMR92 commented 6 years ago

I was in the same spot as you, so I wrote a this as a helper:

private static List<string> GetIncludesFromExpandClause(SelectExpandQueryOption clause)
        {
            var includes = Enumerable.Empty<string>().ToList();

            var includeText = clause != null ? clause.RawExpand : null;
            if (!string.IsNullOrEmpty(includeText))
            {
                foreach (var item in clause.SelectExpandClause.SelectedItems)
                {
                    includes.AddRange(GetExpandedForAutomapper(((ExpandedNavigationSelectItem)item)));
                }
            }

            return includes;
        }

private static List<string> GetExpandedForAutomapper(ExpandedNavigationSelectItem node)
        {
            List<string> automapperGroupIncludes = new List<string>(),
                    automapperSingleIncludes = new List<string>();

            if (node.SelectAndExpand.SelectedItems.Count() > 0)
                foreach (var item in node.SelectAndExpand.SelectedItems)
                {
                    automapperSingleIncludes = GetExpandedForAutomapper((ExpandedNavigationSelectItem)item);
                    foreach (var automapperSingleInclude in automapperSingleIncludes)
                    {
                        automapperGroupIncludes.Add(string.Join(".", new string[] { node.NavigationSource.Name, automapperSingleInclude }));
                    }

                }
            if (automapperGroupIncludes.Count == 0)
                automapperGroupIncludes.Add(node.NavigationSource.Name);

            return automapperGroupIncludes;
        }

Hope it helps!