C# 如何将表值函数作为Web Api 2 OData v4服务中实体集的属性公开?
请告诉我如何将表值函数作为Web Api 2 OData v4服务中实体集的属性公开 我的简化模式有三个表、结构、位置和位置链接。结构包含一个带有节点(locaton)和边(LocationLinks)的图。我使用EntityFramework6数据库访问第一个模型C# 如何将表值函数作为Web Api 2 OData v4服务中实体集的属性公开?,c#,entity-framework,asp.net-web-api,odata,asp.net-web-api-odata,C#,Entity Framework,Asp.net Web Api,Odata,Asp.net Web Api Odata,请告诉我如何将表值函数作为Web Api 2 OData v4服务中实体集的属性公开 我的简化模式有三个表、结构、位置和位置链接。结构包含一个带有节点(locaton)和边(LocationLinks)的图。我使用EntityFramework6数据库访问第一个模型 Simplified Schema Structure: ID Locations: ID ParentID -> Structure LocationLinks
Simplified Schema
Structure:
ID
Locations:
ID
ParentID -> Structure
LocationLinks
A -> Location
B -> Location
目标是访问LocationLinks的structures集合,与访问结构位置的方式相同。i、 e.请求结构#180的图形:
http://.../OData/Structures(180)/LocationLinks
http://.../OData/Structures(180)/Locations
Locations查询自动工作,但我不知道如何添加正确的路由以启用LocationLinks查询。考虑到这会使我的任务更简单,我在SQL server中添加了一个表值函数。该函数存在于my EF模型中,并返回LocationLink实体的集合:
StructureLocationLinks(@StructureID) -> LocationLinks
不幸的是,无论我尝试什么,我似乎都无法使结构(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);
}
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");
}
现在的问题是,我在查询中访问导航属性的能力有限。例如,此链接起作用:
http://.../OData/Structures(180)/Children?$expand=Locations
但事实并非如此
http://.../OData/Structures(180)/Children?$expand=LocationLinks
返回的错误是
{“错误”:{
“代码”:”“消息”:“发生错误”。、“内部错误”:
{
“消息”:“未为“ConnectomeDataModel.Structure”类型定义实例属性“LocationLinks”,
“type”:“System.ArgumentException”,“stacktrace”:“at System.Linq.Expressions.Expression.Property(Expression,
字符串propertyName)\r\n位于
System.Web.OData.Query.Expressions.SelectExpandBinder.CreatePropertyValueExpressionWithFilter(IEdmEntityType
elementType、IEdmProperty属性、表达式源、FilterClause
filterClause)\r\n位于
System.Web.OData.Query.Expressions.SelectExpandBinder.BuildPropertyContainer(IEdmEntityType
elementType,表达式源,Dictionary2属性展开,
ISet1属性包括,ISet1自动选择属性,布尔值
IsSelectingPentypeSegments)\r\n位于
System.Web.OData.Query.Expressions.SelectExpandBinder.ProjectElement(表达式
source,SelectExpandClause SelectExpandClause,IEdmEntityType
entityType)\r\n位于
System.Web.OData.Query.Expressions.SelectExpandBinder.Bind(IQueryable
可查询)\r\n位于
System.Web.OData.Query.ODataQueryOptions.ApplySelectExpand[T](T
实体,ODataQuerySettings查询设置)\r\n位于
System.Web.OData.Query.ODataQueryOptions.ApplyTo(IQueryable查询,
ODataQuerySettings查询设置)\r\n位于
System.Web.OData.EnableQueryAttribute.ExecuteQuery(对象响应,
HttpRequestMessage请求,HttpActionDescriptor actionDescriptor)\r\n
在
System.Web.OData.EnableQueryAttribute.OnActionExecuted(HttpActionExecutedContext
actionExecutedContext)\r\n位于
System.Web.Http.Filters.ActionFilterAttribute.OnActionExecutedAsync(HttpActionExecutedContext
ActionExecuteContext,CancellationToken CancellationToken)\r\n---结束
从引发异常的上一个位置开始的堆栈跟踪的
---\r\n在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务
任务)\r\n位于
System.Runtime.CompilerServices.TaskWaiter.HandleNonSuccessAndDebuggerNotification(任务
任务)\r\n位于
System.Web.Http.Filters.ActionFilterAttribute.d\u 5.MoveNext()\r\n---
来自引发异常的上一个位置的堆栈结束跟踪
---\r\n在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务
任务)\r\n位于
System.Runtime.CompilerServices.TaskWaiter.HandleNonSuccessAndDebuggerNotification(任务
任务)\r\n位于
System.Web.Http.Filters.ActionFilterAttribute.d\u 0.MoveNext()\r\n---
来自引发异常的上一个位置的堆栈结束跟踪
---\r\n在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务
任务)\r\n位于
System.Runtime.CompilerServices.TaskWaiter.HandleNonSuccessAndDebuggerNotification(任务
任务)\r\n位于
System.Runtime.CompilerServices.TaskAwaiter
1.GetResult()\r\n位于
System.Web.Http.Controllers.ActionFilterResult.d\u 2.MoveNext()\r\n---
来自引发异常的上一个位置的堆栈结束跟踪
---\r\n在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务
任务)\r\n位于
System.Runtime.CompilerServices.TaskWaiter.HandleNonSuccessAndDebuggerNotification(任务
任务)\r\n位于
System.Runtime.CompilerServices.TaskWaiter`1.GetResult()\r\n位于
System.Web.Http.Dispatcher.HttpControllerDispatcher.d_u1.MoveNext()
}}}
Xycor
正如您提到的,位置链接
应该与结构的位置
相同。所以,我认为你们为控制器和行动所做的是正确的。我有一个基于您描述的测试,似乎Web API OData可以按照约定路由GetLocationLinks
让我展示我的元数据文档,请忽略名称空间,将其与您的进行比较,并让我知道任何差异。谢谢
<Schema Namespace="ODataConsoleSample" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityType Name="LocationLink">
<Key>
<PropertyRef Name="A" />
<PropertyRef Name="B" />
</Key>
<Property Name="A" Type="Edm.Int64" Nullable="false" />
<Property Name="B" Type="Edm.Int64" Nullable="false" />
</EntityType>
<EntityType Name="Structure">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Edm.Int64" Nullable="false" />
<NavigationProperty Name="Locations" Type="Collection(ODataConsoleSample.Location)" />
<NavigationProperty Name="LocationLinks" Type="Collection(ODataConsoleSample.LocationLink)" />
</EntityType>
<EntityType Name="Location">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Edm.Int64" Nullable="false" />
<Property Name="ParentId" Type="Edm.Int64" Nullable="false" />
</EntityType>
<Function Name="StructureLocationLinks" IsBound="true">
<Parameter Name="bindingParameter" Type="Collection(ODataConsoleSample.Structure)" />
<Parameter Name="StructureID" Type="Edm.Int64" Nullable="false" />
<ReturnType Type="ODataConsoleSample.LocationLink" />
</Function>
<EntityContainer Name="Container">
<EntitySet Name="LocationLinks" EntityType="ODataConsoleSample.LocationLink" />
<EntitySet Name="Structures" EntityType="ODataConsoleSample.Structure">
<NavigationPropertyBinding Path="Locations" Target="Locations" />
<NavigationPropertyBinding Path="LocationLinks" Target="LocationLinks" />
</EntitySet>
<EntitySet Name="Locations" EntityType="ODataConsoleSample.Location" />
</EntityContainer>
</Schema>
这看起来很合理。但是,我认为在配置OData服务时必须添加导航属性。我拥有的EDMX是从数据库生成的。这是EDMX的函数导入。当我将IsBound=“True”属性设置为函数定义时,我得到一个属性not allowed错误。请忽略上面的注释。我无意中发了帖子,当我把它编辑成合适的形状时,它被锁上了。这是正确的回答:看起来很合理。但是,我认为在配置OData服务时,必须将NavigationProperty添加到ODataConventionBuilder。我拥有的EDMX是从数据库生成的。我的功能是d
http://.../OData/Structures(180)/Children?$expand=LocationLinks
<Schema Namespace="ODataConsoleSample" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityType Name="LocationLink">
<Key>
<PropertyRef Name="A" />
<PropertyRef Name="B" />
</Key>
<Property Name="A" Type="Edm.Int64" Nullable="false" />
<Property Name="B" Type="Edm.Int64" Nullable="false" />
</EntityType>
<EntityType Name="Structure">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Edm.Int64" Nullable="false" />
<NavigationProperty Name="Locations" Type="Collection(ODataConsoleSample.Location)" />
<NavigationProperty Name="LocationLinks" Type="Collection(ODataConsoleSample.LocationLink)" />
</EntityType>
<EntityType Name="Location">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Edm.Int64" Nullable="false" />
<Property Name="ParentId" Type="Edm.Int64" Nullable="false" />
</EntityType>
<Function Name="StructureLocationLinks" IsBound="true">
<Parameter Name="bindingParameter" Type="Collection(ODataConsoleSample.Structure)" />
<Parameter Name="StructureID" Type="Edm.Int64" Nullable="false" />
<ReturnType Type="ODataConsoleSample.LocationLink" />
</Function>
<EntityContainer Name="Container">
<EntitySet Name="LocationLinks" EntityType="ODataConsoleSample.LocationLink" />
<EntitySet Name="Structures" EntityType="ODataConsoleSample.Structure">
<NavigationPropertyBinding Path="Locations" Target="Locations" />
<NavigationPropertyBinding Path="LocationLinks" Target="LocationLinks" />
</EntitySet>
<EntitySet Name="Locations" EntityType="ODataConsoleSample.Location" />
</EntityContainer>
</Schema>