我需要帮助找出如何将表值函数公开为Web Api 2 OData v4服务中设置的实体的属性。
我的简化架构有三个表,Structures,Locations和LocationLinks。结构包含带有节点(Locatons)和边(LocationLinks)的图形。我使用Entity Framework 6数据库第一个模型访问。
Simplified Schema
Structure:
ID
Locations:
ID
ParentID -> Structure
LocationLinks
A -> Location
B -> Location
目标是以与访问结构位置相同的方式访问LocationLinks的结构集合。即要求结构#180的图表:
http://.../OData/Structures(180)/LocationLinks
http://.../OData/Structures(180)/Locations
“位置”查询会自动生效,但我无法弄清楚如何添加正确的路线以启用LocationLinks查询。认为它会使我的任务更容易,我已经将一个表值函数添加到我的SQL服务器。该函数存在于我的EF模型中,并返回LocationLink实体的集合:
StructureLocationLinks(@StructureID) -> LocationLinks
不幸的是,无论我尝试什么,我似乎无法使Structure(180)\ LocationLinks URL功能正常。这是我最近的尝试:
StructuresController.cs片段:
// GET: odata/Structures(5)/Locations
[EnableQuery]
public IQueryable<Location> GetLocations([FromODataUri] long key)
{
return db.Structures.Where(m => m.ID == key).SelectMany(m => m.Locations);
}
// GET: odata/Structures(5)/LocationLinks
[EnableQuery]
//[System.Web.OData.Routing.ODataRoute("Structures({key})")]
public IQueryable<LocationLink> GetLocationLinks([FromODataUri] long key)
{
return db.StructureLocationLinks(key);
}
WebApi.cs片段:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.UseDataContractJsonSerializer = true;
//json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All;
//var cors = new System.Web.Http.Cors.EnableCorsAttribute("*", "*", "*");
//config.EnableCors(cors);
// Web API routes
config.MapHttpAttributeRoutes();
ODataConventionModelBuilder builder = GetModel();
config.MapODataServiceRoute(routeName: "odata",
routePrefix: null,
model: builder.GetEdmModel());
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
public static ODataConventionModelBuilder GetModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.Namespace = typeof(Structure).Namespace;
AddLocationLinks(builder);
AddStructures(builder);
builder.EntitySet<Location>("Locations");
return builder;
}
public static void AddStructures(ODataModelBuilder builder)
{
var structSetconfig = builder.EntitySet<Structure>("Structures");
var structConfig = structSetconfig.EntityType;
var functionConfig = structConfig.Collection.Function("StructureLocationLinks");
functionConfig.Parameter<long>("StructureID");
functionConfig.Returns<LocationLink>();
}
public static void AddLocationLinks(ODataModelBuilder builder)
{
var type = builder.EntityType<LocationLink>();
type.HasKey(sl => sl.A);
type.HasKey(sl => sl.B);
builder.EntitySet<LocationLink>("LocationLinks");
}
我收到的错误是:
{ “错误”:{ “code”:“”,“message”:“找不到与请求URI匹配的HTTP资源 。 'http://.../OData/Structures(180)/LocationLinks' “” innererror“:{ “message”:“找不到使用模板为OData路径选择操作的路由约定 '〜/ EntitySet的/关键码/悬而未决' “” 类型 “:””, “堆栈跟踪”: “” }}
基于某些搜索,我尝试将ODataRoute属性添加到控制器:
// GET: odata/Structures(5)/LocationLinks
[EnableQuery]
[System.Web.OData.Routing.ODataRoute("Structures({key})/LocationLinks")]
public IQueryable<LocationLink> GetLocationLinks([FromODataUri] long key)
{
return db.StructureLocationLinks(key);
}
导致此错误:
动作上的路径模板'Structures({key})/ LocationLinks' 控制器'Structures'中的'GetLocationLinks'不是有效的OData 路径模板。找到了一个未解决的路径段“LocationLinks” OData路径模板'Structures({key})/ LocationLinks'。
如何从Structures集合中公开LocationLinks?谢谢你的时间。
修改
我找到这个问题后设法让这个工作: Adding a custom query backed Navigation Property to ODataConventionModelBuilder
我必须在我的ODataConventionBuilder对象上调用.GetEdmModel,然后使用此函数将导航属性添加到模型中:
private static Microsoft.OData.Edm.IEdmModel AddStructureLocationLinks(IEdmModel edmModel)
{
var structures = edmModel.EntityContainer.FindEntitySet("Structures") as EdmEntitySet;
var locationLinks = edmModel.EntityContainer.FindEntitySet("LocationLinks") as EdmEntitySet;
var structType = structures.EntityType() as EdmEntityType;
var locLinksType = locationLinks.EntityType() as EdmEntityType;
var structLocLinksProperty = new EdmNavigationPropertyInfo();
structLocLinksProperty.TargetMultiplicity = Microsoft.OData.Edm.EdmMultiplicity.Many;
structLocLinksProperty.Target = locLinksType;
structLocLinksProperty.ContainsTarget = true;
structLocLinksProperty.OnDelete = Microsoft.OData.Edm.EdmOnDeleteAction.None;
structLocLinksProperty.Name = "LocationLinks";
var navigationProperty = structType.AddUnidirectionalNavigation(structLocLinksProperty);
structures.AddNavigationTarget(navigationProperty, locationLinks);
return edmModel;
}
我现在遇到的问题是我在查询中访问导航属性的能力有限。例如,此链接有效:
http://.../OData/Structures(180)/Children?$expand=Locations
虽然这不是。
http://.../OData/Structures(180)/Children?$expand=LocationLinks
返回的错误是
{“error”:{ “code”:“”,“message”:“发生错误。”,“innererror”: { “message”:“实例属性'LocationLinks'未定义类型'ConnectomeDataModel.Structure'”, “type”:“System.ArgumentException”,“stacktrace”:“at System.Linq.Expressions.Expression.Property(Expression expression, String propertyName)\ r \ n at System.Web.OData.Query.Expressions.SelectExpandBinder.CreatePropertyValueExpressionWithFilter(IEdmEntityType elementType,IEdmProperty属性,Expression source,FilterClause filterClause)\ r \ n at System.Web.OData.Query.Expressions.SelectExpandBinder.BuildPropertyContainer(IEdmEntityType elementType,Expression source,Dictionary
2 propertiesToExpand, ISet
1 propertiesToInclude,ISet1 autoSelectedProperties, Boolean isSelectingOpenTypeSegments)\r\n at System.Web.OData.Query.Expressions.SelectExpandBinder.ProjectElement(Expression source, SelectExpandClause selectExpandClause, IEdmEntityType entityType)\r\n at System.Web.OData.Query.Expressions.SelectExpandBinder.Bind(IQueryable queryable)\r\n at System.Web.OData.Query.ODataQueryOptions.ApplySelectExpand[T](T entity, ODataQuerySettings querySettings)\r\n at System.Web.OData.Query.ODataQueryOptions.ApplyTo(IQueryable query, ODataQuerySettings querySettings)\r\n at System.Web.OData.EnableQueryAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor)\r\n at System.Web.OData.EnableQueryAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)\r\n at System.Web.Http.Filters.ActionFilterAttribute.OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter
1.GetResult()\ r \ n at System.Web.Http.Controllers.ActionFilterResult.d__2.MoveNext(个)\ r \ n --- 从抛出异常的先前位置开始的堆栈跟踪结束 --- \ r \ n在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)\ r \ n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)\ r \ n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\ r \ n at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()” }}
答案 0 :(得分:0)
Xycor
如您所述,LocationLinks
应与Locations
的{{1}}相同。所以,我认为你为控制器和行动所做的是正确的。我根据您的描述进行了测试,似乎Web API OData可以按惯例路由Structure
。
让我展示我的元数据文档,请忽略命名空间并与您的名称空间进行比较,让我知道任何不同之处。感谢。
GetLocationLinks