2016-03-16 11 views
0

假設我們有兩個實體ParentChild,ChildParent(爲了本示例而爲1:1)的導航屬性。可以使用此請求獲取特定父母的孩子:http://example.com/Parent(1)/Child。爲了完成這項工作,必須在ParentController中提供GetChild()方法來提取正確的Child實體。使用OData和實體框架,我可以加載導航屬性而無需爲每個關係編寫getter方法?

Microsoft.OData.ClientLoadProperty方法,可以讓你在這樣的需求獲取導航屬性:

var parent = container.Parents.ByKey(1).GetValue(); 
container.LoadProperty(parent, "Child"); 

但由於LoadProperty內部創建一個http://example.com/Parent(1)/Child請求,調用失敗,如果我不寫了GetChild()方法:

未找到路由約定來爲模板「〜/ entityset/key/navigation」選擇OData路徑的操作。

在具有許多導航屬性的項目中,編寫所有getter方法可能需要很多工作。有沒有一種方法來加載導航屬性,而不必爲每一個關係寫getters?

編輯:我應該清楚,我所知道的$expand - 但有時它需要的初始請求後長時間來獲取相關的實體(這是LoadProperty()做的,什麼需要爲每一個getter單一關係)。

+0

你看過$ expand? http://example.com/Parent?$expand=Child http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/using-select-expand-and-值 –

回答

1

OData支持inline expansion of related entities

var parent = container.Parents.ByKey(1).Expand(p => p.Child).GetValue(); 

此調用將導致類似於HTTP請求:

GET http://example.com/Parent(1)?$expand=Child 

則可以在可以通過使用Expand<T>方法通過ByKey返回的對象上進行如下解決客戶端上的這個問題也連鎖撥打Expand<T>

+0

謝謝,我知道'$ expand'。有時希望在初始請求之後很長時間獲取相關實體,儘管(這是'LoadProperty()'的作用)。但正如我原來的問題所述,使用'LoadProperty()'有必要爲每一個關係寫一個getter。 – hingst

0

假設您可以修改服務器端代碼,您可以編寫自定義路由約定和基本控制器類來動態地處理某些或全部導航路由。

這個自定義路由公約只處理GET的形式~/entityset/key/navigation途徑請求,並選擇命名的動作或者GetRelatedEntityCollectionGetRelatedSingleEntity(取決於導航屬性是否引用集合或單一實體)。

public class DynamicNavigationRoutingConvention : NavigationSourceRoutingConvention 
{ 
    public override string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, ILookup<string, HttpActionDescriptor> actionMap) 
    { 
     if (controllerContext.Request.Method != HttpMethod.Get || odataPath.PathTemplate != "~/entityset/key/navigation") 
     { 
      return null; 
     } 

     NavigationPathSegment navigationSegment = odataPath.Segments.Last() as NavigationPathSegment; 
     IEdmNavigationProperty navigationProperty = navigationSegment.NavigationProperty; 
     IEdmEntityType declaringType = navigationProperty.DeclaringType as IEdmEntityType; 

     if (declaringType == null) 
     { 
      return null; 
     } 

     string actionName = navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many 
      ? "GetRelatedEntityCollection" : "GetRelatedSingleEntity"; 

     if (!actionMap.Contains(actionName)) 
     { 
      return null; 
     } 

     KeyValuePathSegment keyValueSegment = odataPath.Segments[1] as KeyValuePathSegment; 
     controllerContext.RouteData.Values[ODataRouteConstants.Key] = keyValueSegment.Value; 

     // Add information about the specific navigation property. If you need 
     // more than just the name, add additional items to RouteData.Values. 
     controllerContext.RouteData.Values["navigationProperty"] = navigationProperty.Name; 

     return actionName; 
    } 
} 

修改您的OData配置,以確保自定義路由約定的實例標準NavigationRoutingConvention之前發生(以覆蓋~/entityset/key/navigation路線的處理)。

var routingConventions = ODataRoutingConventions.CreateDefault(); 
    routingConventions.Insert(0, new DynamicNavigationRoutingConvention()); 

    config.MapODataServiceRoute(
     routeName: "odata", 
     routePrefix: null, 
     model: model, 
     pathHandler: new DefaultODataPathHandler(), 
     routingConventions: routingConventions 
    ); 

以下基本控制器類將草繪自定義路由約定所期望的方法。請注意,navigationProperty參數與路由約定中的HttpControllerContext.RouteData.Values中的一個密鑰具有相同的名稱。

​​

您可能要改變返回類型的這些方法(即IQueryable<TEntity>TEntity,分別),以充分利用的OData內置的查詢組成。

相關問題