Cosmos DB嵌套Individual Task部分更新遇对象未实例化错误求助
问题背景
尝试更新Cosmos DB中存储的JSON文档里嵌套的IndividualTask对象,使用PatchOperation.Set或PatchOperation.Replace均抛出**"Object Not Set To An Instance Of An Object"**错误。已提前查询获取IndividualTaskSets和IndividualTask的数组索引(因它们位置不固定),同时使用过滤谓词定位目标IndividualTask(一个IndividualTaskSets下包含多个该对象)。
数据模型示例
{ "GroupTask": [ { "_type": null, "GroupTaskID": "GUID", "GroupTaskTitle": null, "GroupTaskDescription": null, "IndividualTaskSets": [ { "SETID": "GUID", "CreatedBy": "", "CreatedDate": "0001-01-01T00:00:00", "IndividualTask": [ { "IndividualTaskID": "GUID", "TaskStatus": "", "TaskTitle": "", "TaskType": "", "TaskDescription": "", "TaskNotes": "", "Priority": "Normal", "CreatedBy": "", "CreatedDate": "0001-01-01T00:00:00" } ] } ] } ], "CaseID": "GUID", "TenantID": "testtenant0004", "id": "GUID", "TaskID": "GUID" }
使用的过滤谓词字符串
"FROM Task t JOIN g in t.GroupTask JOIN its IN g.IndividualTaskSets JOIN it IN its.IndividualTask WHERE it.IndividualTaskID ='" + itid + "'"
更新方法代码
public async Task<string> UpdateIT(ReturnTaskObject rto, IndividualTask updatedIT, string path) { try { PatchItemRequestOptions patchItemRequestOptions = new PatchItemRequestOptions { FilterPredicate = path }; ItemResponse<IndividualTask> response = await container.PatchItemAsync<IndividualTask>( id: rto.id, partitionKey: new Microsoft.Azure.Cosmos.PartitionKey(rto.taskid), patchOperations: new[] { PatchOperation.Set("/IndividualTaskSets/" + rto.individualtasksetidorindex + "/IndividualTask/" + rto.individualtaskidorindex + "/", updatedIT)}, // 曾尝试去掉过滤谓词,结果报错相同 // patchOperations: new[] { PatchOperation.Replace("/GroupTask/0/IndividualTaskSets/" + rto.individualtasksetidorindex + "/IndividualTask/" + rto.individualtaskidorindex + "/", updatedIT) } requestOptions: patchItemRequestOptions ); string status = response.StatusCode.ToString(); return status; } catch (Exception e) { return e.Message; } }
完整堆栈跟踪
at CMaaS.Task.Service.DBUtil.UpdateIT(ReturnTaskObject rto, IndividualTask updatedIT, String path) at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine) at CMaaS.Task.Service.DBUtil.UpdateIT(ReturnTaskObject rto, IndividualTask updatedIT, String path) at System.Dynamic.UpdateDelegates.UpdateAndExecute4[T0,T1,T2,T3,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2, T3 arg3) at CMaaS.Task.Function.FunctionTaskController.RunUpdateIndividualTaskSetAsync(HttpRequest req, ILogger log) at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine) at CMaaS.Task.Function.FunctionTaskController.RunUpdateIndividualTaskSetAsync(HttpRequest req, ILogger log) at lambda_method149(Closure , FunctionTaskController , Object[] ) at Microsoft.Azure.WebJobs.Host.Executors.TaskMethodInvoker`2.InvokeAsync(TReflected instance, Object[] arguments) at Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker`2.InvokeAsync(Object instance, Object[] arguments) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() at System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.<>c.<OutputCorrelationEtwEvent>b__6_0(Action innerContinuation, Task continuationIdTask) at System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke() at System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.RunAction(Object state) at System.Threading.QueueUserWorkItemCallbackDefaultContext.Execute() at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart() at System.Threading.Thread.StartCallback()
排查与解决要点
修复Patch路径完整性
原始代码中第一个Patch路径/IndividualTaskSets/...错误,因为IndividualTaskSets并非根节点直接属性,而是嵌套在GroupTask数组内。正确路径需包含GroupTask的索引层级,比如:PatchOperation.Set($"/GroupTask/{rto.groupTaskIndex}/IndividualTaskSets/{rto.individualtasksetidorindex}/IndividualTask/{rto.individualtaskidorindex}", updatedIT)确保你已获取到
GroupTask数组的正确索引(不能硬编码为0,需通过查询动态获取)。过滤谓词语法修正
PatchItemRequestOptions.FilterPredicate仅需要WHERE子句的内容,而非完整SQL语句。正确写法应为:FilterPredicate = $"it.IndividualTaskID = '{itid}'"注意:该谓词是用来判断是否执行Patch操作(当文档满足条件时才更新),而非定位嵌套对象,嵌套对象的定位仍需依赖Patch路径中的数组索引。
验证索引有效性
确认rto.individualtasksetidorindex和rto.individualtaskidorindex是数字类型的数组索引,而非GUID字符串。Patch路径中数组元素需通过索引位置访问,无法直接用ID定位。泛型参数匹配文档类型
PatchItemAsync的泛型参数应与整个文档的类型一致,而非嵌套的IndividualTask。比如如果你的文档类型是TaskDocument,则应改为:ItemResponse<TaskDocument> response = await container.PatchItemAsync<TaskDocument>(...)使用错误的泛型类型可能导致序列化/反序列化异常,间接引发空引用错误。
内容的提问来源于stack exchange,提问作者Kuruption

