将自定义查询支持的导航属性添加到ODataConventionModelBuilder
情况
我创建了以下Model类
public class Car { public int Id {get;set;} public string Name {get;set;} public virtual ICollection PartStates {get;set; } } public class PartState { public int Id {get;set;} public string State {get;set;} public int CarId {get;set;} public virtual Car Car {get;set;} public int PartId {get;set;} public virtual Part Part {get;set;} } public class Part { public int Id {get;set;} public string Name {get;set;} }
和一个匹配的DbContext
public class CarContext : DbContext { public DbSet Cars {get;set;} public DbSet PartStates {get;set;} public DbSet Parts {get;set;} }
并创建了一个WebApplication,通过odata使用脚手架模板“Web API 2 OData Controller with Actions,using Entity Framework”
我还创建了以下webapi配置:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { var builder = new ODataConventionModelBuilder(); builder.EntitySet("Cars"); builder.EntitySet("PartStates"); builder.EntitySet("Parts"); var edmModel = builder.GetEdmModel(); config.Routes.MapODataRoute("odata", "odata", edmModel); } }
我现在想要将以下方法添加到我的汽车控制器中
// GET: odata/Cars(5)/Parts [Queryable] public IQueryable GetParts([FromODataUri] int key) { var parts = db.PartStates.Where(s => s.CarId == key).Select(s => s.Part).Distinct(); return parts; }
并使用此Url检索数据:
https://localhost/odata/Cars(1)/Parts
但它不起作用,而是我得到以下错误:
{ "odata.error":{ "code":"","message":{ "lang":"en-US","value":"No HTTP resource was found that matches the request URI 'https://localhost/odata/Cars(1)/Parts'." },"innererror":{ "message":"No routing convention was found to select an action for the OData path with template '~/entityset/key/unresolved'.","type":"","stacktrace":"" } } }
题
所以我的问题是,甚至可能吗?!
我尝试手动创建一个Navigation属性,并将其添加到edm模型,虽然这确实解决了调用新方法的问题,但它也引入了新的错误。
编辑:
什么id尝试以这种方式手动添加它:
var edmModel = (EdmModel)builder.GetEdmModel(); var carType = (EdmEntityType)edmModel.FindDeclaredType("Car"); var partType = (EdmEntityType)edmModel.FindDeclaredType("Part"); var partsProperty = new EdmNavigationPropertyInfo(); partsProperty.TargetMultiplicity = EdmMultiplicity.Many; partsProperty.Target = partType; partsProperty.ContainsTarget = false; partsProperty.OnDelete = EdmOnDeleteAction.None; partsProperty.Name = "Parts"; var carsProperty = new EdmNavigationPropertyInfo(); carsProperty.TargetMultiplicity = EdmMultiplicity.Many; carsProperty.Target = carType; carsProperty.ContainsTarget = false; carsProperty.OnDelete = EdmOnDeleteAction.None; carsProperty.Name = "Cars"; var nav = EdmNavigationProperty.CreateNavigationPropertyWithPartner(partsProperty, carsProperty); carType.AddProperty(nav); config.Routes.MapODataRoute("odata", "odata", edmModel);
虽然这允许我通过上面指定的URL调用上面的speciefied方法,它给了我以下错误:
{ "odata.error":{ "code":"","message":{ "lang":"en-US","value":"An error has occurred." },"innererror":{ "message":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; odata=fullmetadata; charset=utf-8'.","type":"System.InvalidOperationException","stacktrace":"","internalexception":{ "message":"The related entity set could not be found from the OData path. The related entity set is required to serialize the payload.","type":"System.Runtime.Serialization.SerializationException","stacktrace":" at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteObject(Object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)rn at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders)rn at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)rn--- End of stack trace from previous location where exception was thrown ---rn at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)rn at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)rn at System.Runtime.CompilerServices.TaskAwaiter.GetResult()rn at System.Web.Http.WebHost.HttpControllerHandler.d__1b.MoveNext()" } } } }
您必须在EntitySet上调用“AddNavigationTarget”。 假设您的命名空间是“MyNamespace”,然后将以下代码添加到WebApiConfig.cs。 通过这种方式,使用“Get:odata / Cars(1)/ Parts”检索数据将起作用。
var cars = (EdmEntitySet)edmModel.EntityContainers().Single().FindEntitySet("Cars"); var parts = (EdmEntitySet)edmModel.EntityContainers().Single().FindEntitySet("Parts"); var carType = (EdmEntityType)edmModel.FindDeclaredType("MyNamespace.Car"); var partType = (EdmEntityType)edmModel.FindDeclaredType("MyNamespace.Part"); var partsProperty = new EdmNavigationPropertyInfo(); partsProperty.TargetMultiplicity = EdmMultiplicity.Many; partsProperty.Target = partType; partsProperty.ContainsTarget = false; partsProperty.OnDelete = EdmOnDeleteAction.None; partsProperty.Name = "Parts"; cars.AddNavigationTarget(carType.AddUnidirectionalNavigation(partsProperty), parts);
进一步考虑@ FengZhao的答案,为了使url odata / Cars正常工作,您还需要将导航属性链接构建器注册到实体集链接构建器。
var cars = (EdmEntitySet)edmModel.EntityContainers().Single().FindEntitySet("Cars"); var parts = (EdmEntitySet)edmModel.EntityContainers().Single().FindEntitySet("Parts"); var carType = (EdmEntityType)edmModel.FindDeclaredType("MyNamespace.Car"); var partType = (EdmEntityType)edmModel.FindDeclaredType("MyNamespace.Part"); var partsProperty = new EdmNavigationPropertyInfo(); partsProperty.TargetMultiplicity = EdmMultiplicity.Many; partsProperty.Target = partType; partsProperty.ContainsTarget = false; partsProperty.OnDelete = EdmOnDeleteAction.None; partsProperty.Name = "Parts"; var navigationProperty = carType.AddUnidirectionalNavigation(partsProperty); cars.AddNavigationTarget(navigationProperty, parts); var linkBuilder = edmModel.GetEntitySetLinkBuilder(cars); linkBuilder.AddNavigationPropertyLinkBuilder(navigationProperty, new NavigationLinkBuilder((context, property) => context.GenerateNavigationPropertyLink(property, false), true));
Web Api无法针对任何已注册的URI模板解析您的URL。
使用Route Debugger来解决这个问题。 https://blogs.msdn.com/b/webdev/archive/2013/04/04/debugging-asp-net-web-api-with-route-debugger.aspx
我相信我们的问题是您通过url传递的id
参数尝试使其更明确
上述就是C#学习教程:将自定义查询支持的导航属性添加到ODataConventionModelBuilder分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
config.Routes.MapHttpRoute ( "DefaultInternalApi", "api/{controller}/{objectType}/{Id}/{relation}", defaults: new { Id = System.Web.Http.RouteParameter.Optional, } );
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1043234.html