OData / RESTier

A turn-key library for building RESTful services
http://odata.github.io/RESTier
Other
471 stars 137 forks source link

Problems adding Entities / Related Entities #759

Open slnetgit opened 4 months ago

slnetgit commented 4 months ago

Short summary (3-5 sentences) describing the issue.
Adding new Entity with Savechengesoption.Batch) with related Entit(ies) from Dataservicecollection does not work as expected

Assemblies affected

For Information: Project references server:

TargetFramework>net8.0 UserSecretsId>0747c9f0-3a8d-4969-a360-a7dc2e7f8489 PlatformTarget>x64 "IBM.EntityFrameworkCore" Version="8.0.0.200" /> "Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.16" /> "Microsoft.AspNetCore.DataProtection" Version="7.0.2" /> "Microsoft.EntityFrameworkCore.Design" Version="8.0.5"> "Microsoft.Extensions.Configuration" Version="7.0.0" /> "Microsoft.OData.ModelBuilder" Version="1.0.9" /> "Microsoft.Restier.AspNetCore" Version="1.1.0" /> "Microsoft.Restier.Core" Version="1.1.0" /> "Microsoft.Restier.EntityFrameworkCore" Version="1.1.0" /> "Newtonsoft.Json" Version="13.0.3" /> Swashbuckle.AspNetCore" Version="6.5.0" /> ### Reproduce steps I want to add new Element with related elements. relation is 1:n car key is nr box key is car_nr, nr the described issue is on DataServiceCollection cars = new DataServiceCollection(context); car newcar = new car() { nr = "test1", such = "test1",name="Test",kennzeichen="hallo" }; newcar.boxes.Add(new box() {car_nr="test1", nr = 1, dompos = 1,art_nr=""}); cars.Add(newcar); context.SaveChanges(SaveChangesOptions.BatchWithSingleChangeset); // causes exception ### Expected result In WCF Odata V3 with Savechanges(Batch) this works as expected. New car is created with boxes. No need to enter car_id in every box created When I use restier 1 or 1.1 i have to use context.SaveChanges(); // works but causes single requests and neds car_id in box . No transaction around request. ### Actual result when I use cont.SaveChanges(SaveChangesOptions.BatchWithSingleChangeset) this results in a strange Error message Stacktrace: Microsoft.OData.Core.dll!Microsoft.OData.UriParser.ODataPathParser.CreateDynamicPathSegment(Microsoft.OData.UriParser.ODataPathSegment previous, string identifier, string parenthesisExpression) Unbekannt Microsoft.OData.Core.dll!Microsoft.OData.UriParser.ODataPathParser.CreateFirstSegment(string segmentText) Unbekannt Microsoft.OData.Core.dll!Microsoft.OData.UriParser.ODataPathParser.ParsePath(System.Collections.Generic.ICollection segments) Unbekannt Microsoft.OData.Core.dll!Microsoft.OData.UriParser.ODataPathFactory.BindPath(System.Collections.Generic.ICollection segments, Microsoft.OData.UriParser.ODataUriParserConfiguration configuration) Unbekannt Microsoft.OData.Core.dll!Microsoft.OData.UriParser.ODataUriParser.ParsePathImplementation() Unbekannt Microsoft.OData.Core.dll!Microsoft.OData.UriParser.ODataUriParser.Initialize() Unbekannt Microsoft.OData.Core.dll!Microsoft.OData.UriParser.ODataUriParser.ParsePath() Unbekannt Microsoft.AspNetCore.OData.dll!Microsoft.AspNet.OData.Routing.DefaultODataPathHandler.Parse(string serviceRoot, string odataPath, System.IServiceProvider requestContainer, bool template) Unbekannt Microsoft.AspNetCore.OData.dll!Microsoft.AspNet.OData.Routing.DefaultODataPathHandler.Parse(string serviceRoot, string odataPath, System.IServiceProvider requestContainer) Unbekannt Microsoft.AspNetCore.OData.dll!Microsoft.AspNet.OData.Routing.ODataPathRouteConstraint.GetODataPath(string oDataPathString, string uriPathString, string queryString, System.Func requestContainerFactory) Unbekannt Microsoft.AspNetCore.OData.dll!Microsoft.AspNet.OData.Routing.ODataPathRouteConstraint.Match(Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Routing.IRouter route, string routeKey, Microsoft.AspNetCore.Routing.RouteValueDictionary values, Microsoft.AspNetCore.Routing.RouteDirection routeDirection) Unbekannt Microsoft.AspNetCore.Routing.dll!Microsoft.AspNetCore.Routing.RouteConstraintMatcher.Match(System.Collections.Generic.IDictionary constraints, Microsoft.AspNetCore.Routing.RouteValueDictionary routeValues, Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Routing.IRouter route, Microsoft.AspNetCore.Routing.RouteDirection routeDirection, Microsoft.Extensions.Logging.ILogger logger) Unbekannt Microsoft.AspNetCore.Routing.dll!Microsoft.AspNetCore.Routing.RouteBase.RouteAsync(Microsoft.AspNetCore.Routing.RouteContext context) Unbekannt Microsoft.AspNetCore.Routing.dll!Microsoft.AspNetCore.Routing.RouteCollection.RouteAsync(Microsoft.AspNetCore.Routing.RouteContext context) Unbekannt Microsoft.AspNetCore.Routing.dll!Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(Microsoft.AspNetCore.Http.HttpContext httpContext) Unbekannt > Microsoft.Restier.AspNetCore.dll!Microsoft.Restier.AspNetCore.Middleware.ODataBatchHttpContextFixerMiddleware.InvokeAsync(Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Http.IHttpContextAccessor contextAccessor) Zeile 21 C# Microsoft.AspNetCore.OData.dll!Microsoft.AspNet.OData.Batch.ODataBatchRequestItem.SendRequestAsync(Microsoft.AspNetCore.Http.RequestDelegate handler, Microsoft.AspNetCore.Http.HttpContext context, System.Collections.Generic.IDictionary contentIdToLocationMapping) Unbekannt Microsoft.Restier.AspNetCore.dll!Microsoft.Restier.AspNetCore.Batch.RestierBatchChangeSetRequestItem.SendRequestAsync(Microsoft.AspNetCore.Http.RequestDelegate handler) Zeile 38 C# Microsoft.AspNetCore.OData.dll!Microsoft.AspNet.OData.Batch.DefaultODataBatchHandler.ExecuteRequestMessagesAsync(System.Collections.Generic.IEnumerable requests, Microsoft.AspNetCore.Http.RequestDelegate handler) Unbekannt Microsoft.AspNetCore.OData.dll!Microsoft.AspNet.OData.Batch.DefaultODataBatchHandler.ProcessBatchAsync(Microsoft.AspNetCore.Http.HttpContext context, Microsoft.AspNetCore.Http.RequestDelegate nextHandler) Unbekannt in OdataUtriParser the Uri which has to be pasrsed is :http://192.168.0.87:5000/$121/boxes I think when handling the call as a Batch the batch should be splitted in the single operations but somehow this gets lost during the call. Do yo have a hint ? in OdataPathParser this stops with private void CreateDynamicPathSegment(ODataPathSegment previous, string identifier, string parenthesisExpression) { if (configuration.ParseDynamicPathSegmentFunc != null) { ICollection collection = configuration.ParseDynamicPathSegmentFunc(previous, identifier, parenthesisExpression); parsedSegments.AddRange(collection); return; } if (previous == null) { >>>>>> here throw ExceptionUtil.CreateResourceNotFoundError(identifier); >>> identifier is $121 } Expected Behavior : Correct Insert in Batch with single changeset For using this as a successor to wcf odata it is essential for me to be able to update Contexts with savechanges Batch handling in a Transaction. ### Additional details Aditionally 2) Problem when related entity does not have id of master Entity In the box Entities I have to add the kfz nr, otherwise the insert will not happen. Neither with context.Savechanges() nor with context.SaveChanges(SaveChangesOptions.BatchWithSingleChangeset) If I enter Null as Kfz Nr I get an Exception that the column does not allow null values, If I Enter an Empty string, Just a new Item with Empty kfz_nr is created. Expected Bahavior: Savechanges should work like in Wcf Odata V3 with no need to add number of Master Entity in the related entity . 3) Next problem with entity references When the entity box contains an object reference to the car entity this causes an exception that the payload should not contain navigation properties Expected behavior: References within the object structure should not cause problems in updating object graphs
slnetgit commented 3 weeks ago

There has been an issue Batch Transaction Support #122 which should be solved, but when I try SaveChenges using the batch option to get one transaction this fails in the way described above