OData / odata.net

ODataLib: Open Data Protocol - .NET Libraries and Frameworks
https://docs.microsoft.com/odata
Other
682 stars 348 forks source link

How to prevent error: "The current change set contains too many operations." #2726

Open francisharvey opened 12 months ago

francisharvey commented 12 months ago

Hi,

I send multiple records in a performance test and I hit this limit.

"The current change set contains too many operations. A maximum number of '5000' operations are allowed in a change set."

I could not found any information on how to prevent the error, perhaps by splitting the change set operations in two or sending only half of the changes in an my batch operation...

Is there a way to do something when I suspect the change set is too big?

I use BeginSaveChanges with both BatchWithSingleChangeset and PostOnlySetProperties...

Thanks Francis Harvey

leoerlandsson commented 11 months ago

Hi,

Please see the MessageReaderSettings.MessageQuotas.MaxOperationsPerChangeset parameter.

You can increase this, but 5000 is a lot of operations, so perhaps consider splitting the change set as you suggest yourself.

Br, Leo

wachugamaina commented 11 months ago

Please let us know if increasing the MessageReaderSettings.MessageQuotas.MaxOperationsPerChangeset limit sorts the issue. Thanks.

gathogojr commented 11 months ago

Hi @francisharvey. Did you get a chance to try out the suggestions provided?

francisharvey commented 11 months ago

@wachugamaina @gathogojr In fact guys, I don't know how to set this parameter...

How can I access the MessageReaderSettings class from the DataServiceContext ?

@leoerlandsson Suggesting and doing is two different thing, this is why I ask about it.

How can I split the changeset of a DataServiceContext instance?

FYI, I'm using the odata nuget v7.7.1, not the latest one, but only a few version behind.

Thanks a lot! Francis Harvey

leoerlandsson commented 11 months ago

@francisharvey You'll need to allow that many operations server side aswell. Here's how we do that:

var odataBatchHandler = new DefaultODataBatchHandler();

odataBatchHandler.MessageQuotas.MaxOperationsPerChangeset = 500; odataBatchHandler.MessageQuotas.MaxPartsPerBatch = 500;

services.AddControllers() .AddOData(opts => { opts.AddRouteComponents( ApiRoot, ODataEdmModel.GetEdmModel(), sp => { sp.AddSingleton(odataBatchHandler); sp.AddSingleton(new ODataMessageReaderSettings(ODataVersion.V401) { MessageQuotas = odataBatchHandler.MessageQuotas }); });

I'll check if I can help you with specific code for client side aswell.

Regarding splitting the changeset - just do 2 (or more) calls with 5000 records.

For splitting the list of objects to update you can use e.g. Linq Batch().

francisharvey commented 11 months ago

@leoerlandsson Thank you, but unfortunately I'm only consuming service from servers I do not own (D365 BusinessCentral, D365 Finance & Operation, etc...)

So what I'm trying to do is on the client side with DataServiceContext.

The fact is when I get to call the SaveChanges method, all objects have been processed and added to the single instance of the context...

The DataServiceContext has an entityTracker in where you can see tracked changes but nothing to interact with the list or control the way these changes will be sent.

In case it took an hour creating the entities, fill properties and link them, I would like to be able to control the quantity of request that comes out at the same time to prevent the error, instead of getting an error message without any way to work around it.

For now when I get the error I remove the batch option and call SaveChanges again, but i guess the batch requests would perform better than the normal ones...

Francis Harvey