You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Telerik OpenAccess「Change operation canceled by user」异常解析与排查

Telerik OpenAccess「Change operation canceled by user」异常排查记录

我正在开发一款基于另一应用的程序,两者均依赖Telerik OpenAccess读取SQL Server数据库,客户频繁遇到以下异常:

Telerik.OpenAccess.OpenAccessException: Change operation canceled by user.
   at OpenAccessRuntime.ExceptionWrapper.Throw()
   at OpenAccessRuntime.DataObjects.PCStateMan.handleException(Exception x)
   at OpenAccessRuntime.DataObjects.PCStateMan.SetField[T](PersistenceCapable _pc, Int32 field, T currentValue, T newValue)
   at App1.Server.Core.Domain.CommandOrderPart.OpenAccessEnhancedSet_status(CommandOrderPart owner, OrderStatus value)
   at App1.Server.Core.Domain.CommandOrderPart.set_Status(OrderStatus value)
   at App2.Helpers.ExtensionMethods.SetStatus(CommandOrderPart orderPart, String status) in C:\Source1.cs:line 47
   at App2.Manager.RequestOrderStatus(JbtOrder order) in C:\Source2.cs:line 668 
Telerik.OpenAccess.OpenAccessException: Change operation canceled by user.
   at OpenAccessRuntime.ExceptionWrapper.Throw()
   at OpenAccessRuntime.DataObjects.PCStateMan.handleException(Exception x)
   at OpenAccessRuntime.DataObjects.PCStateMan.SetField[T](PersistenceCapable _pc, Int32 field, T currentValue, T newValue)
   at App1.Server.Core.Domain.CommandOrderPart.OpenAccessEnhancedSet_status(CommandOrderPart owner, OrderStatus value)
   at App1.Server.Core.Domain.CommandOrderPart.set_Status(OrderStatus value)
   at App2.Helpers.ExtensionMethods.SetStatus(CommandOrderPart orderPart, String status) in C:\Source1.cs:line 47
   at App2.Manager.RequestOrderStatus(JbtOrder order) in C:\Source2.cs:line 668

需要解决的疑问:

  • 「Change operation canceled by user」具体含义是什么?
  • 触发该异常的「用户」是谁?
  • 能否从数据库获取更多信息?涉及哪些表、视图或诊断方式?

反编译Telerik OpenAccess DLL分析

反编译Telerik OpenAccess DLL后,找到两处「Change operation canceled by user」的触发逻辑:

  1. DisconnectedStateManager.cs 文件:
private ChangeEventArgs FireChanging(
  object pc,
  int field,
  object oldV,
  object newV)
{
  ChangeEventArgs ev = new ChangeEventArgs(pc, this.cmd.getFieldName(field), oldV, newV, this.state == (short) 4, true);
  this.repository.tracker.FireChanging(ev);
  return !ev.Cancel ? ev : throw new OpenAccessException("Change operation canceled by user.", true);
}
  1. SPI/TrackingImpl.cs 文件:
/// <summary>Raises the Changing event.</summary>
/// <remarks>Not intended for application use.</remarks>
/// <param name="ev">The event to raise.</param>
public void FireChanging(ChangeEventArgs ev)
{
  if (this.evChanging == null)
    return;
  this.evChanging(this.owner, ev);
  if (ev.Cancel)
    throw new OpenAccessException("Change operation canceled by user.", true);
}

PcStateMan.cs异常处理逻辑

在「PcStateMan.cs」的handleException(...)方法中可见:

private void handleException(Exception x)
{
  if (BindingSupportImpl.Instance.isOwnException(x))
    throw new ExceptionWrapper(x).Throw();
  throw BindingSupportImpl.Instance.internally(x.Message, x).Throw();
}

这意味着BindingSupportImpl.Instance.isOwnException(x)条件为真(暂不明确具体含义)。


应用数据库超时排查

若App1和/或App2配置了超时,可能引发该问题(例如App1.....CommandOrderPart.Set()执行过久,而App2设置了数据库超时)。这些超时配置在哪里查看?


排查触发问题的SQL语句

问题显然出在修改App1.....CommandOrderPart状态时,可创建SQL追踪监控该对象的所有事务,脚本如下:

DECLARE @TraceID INT;
DECLARE @MaxFileSize BIGINT = 50; -- File size limit in MB
DECLARE @TraceFilePath NVARCHAR(256) = N'C:\SQLTraces\Trace_OrderPart'; -- Base trace file path

-- Step 1: Create a new trace
EXEC sp_trace_create 
    @traceid = @TraceID OUTPUT,
    @options = 2, -- File rollover enabled
    @tracefile = @TraceFilePath,
    @maxfilesize = @MaxFileSize,
    @stoptime = NULL; -- No automatic stop

-- Step 2: Set events to capture
-- Add events to monitor SQL statements and related information
EXEC sp_trace_setevent @TraceID, 16,  1, 1; -- EventClass (SP:Attention) TextData
EXEC sp_trace_setevent @TraceID, 16,  4, 1; -- EventClass (SP:Attention) TransactionId
EXEC sp_trace_setevent @TraceID, 16,  9, 1; -- EventClass (SP:Attention) ClientProcessID
EXEC sp_trace_setevent @TraceID, 16, 10, 1; -- EventClass (SP:Attention) ApplicationName
EXEC sp_trace_setevent @TraceID, 16, 11, 1; -- EventClass (SP:Attention) LoginName
EXEC sp_trace_setevent @TraceID, 16, 12, 1; -- EventClass (SP:Attention) SPID
EXEC sp_trace_setevent @TraceID, 16, 13, 1; -- EventClass (SP:Attention) ClientProcessID
EXEC sp_trace_setevent @TraceID, 16, 14, 1; -- EventClass (SP:Attention) StartTime
EXEC sp_trace_setevent @TraceID, 16, 15, 1; -- EventClass (SP:Attention) EndTime
EXEC sp_trace_setevent @TraceID, 16, 20, 1; -- EventClass (SP:Attention) Severity
EXEC sp_trace_setevent @TraceID, 16, 23, 1; -- EventClass (SP:Attention) Success
EXEC sp_trace_setevent @TraceID, 16, 25, 1; -- EventClass (SP:Attention) IntegerData
EXEC sp_trace_setevent @TraceID, 16, 27, 1; -- EventClass (SP:Attention) EventClass
EXEC sp_trace_setevent @TraceID, 16, 31, 1; -- EventClass (SP:Attention) Error Number
EXEC sp_trace_setevent @TraceID, 16, 34, 1; -- EventClass (SP:Attention) ObjectName
EXEC sp_trace_setevent @TraceID, 16, 49, 1; -- EventClass (SP:Attention) RequestID
EXEC sp_trace_setevent @TraceID, 16, 55, 1; -- EventClass (SP:Attention) IntegerData2

EXEC sp_trace_setevent @TraceID, 40,  1, 1; -- EventClass (SP:StmtStarting) TextData
EXEC sp_trace_setevent @TraceID, 40,  4, 1; -- EventClass (SP:StmtStarting) TransactionId
EXEC sp_trace_setevent @TraceID, 40,  9, 1; -- EventClass (SP:StmtStarting) ClientProcessID
EXEC sp_trace_setevent @TraceID, 40, 10, 1; -- EventClass (SP:StmtStarting) ApplicationName
EXEC sp_trace_setevent @TraceID, 40, 11, 1; -- EventClass (SP:StmtStarting) LoginName
EXEC sp_trace_setevent @TraceID, 40, 12, 1; -- EventClass (SP:StmtStarting) SPID
EXEC sp_trace_setevent @TraceID, 40, 13, 1; -- EventClass (SP:StmtStarting) ClientProcessID
EXEC sp_trace_setevent @TraceID, 40, 14, 1; -- EventClass (SP:StmtStarting) StartTime
EXEC sp_trace_setevent @TraceID, 40, 15, 1; -- EventClass (SP:StmtStarting) EndTime
EXEC sp_trace_setevent @TraceID, 40, 20, 1; -- EventClass (SP:StmtStarting) Severity
EXEC sp_trace_setevent @TraceID, 40, 23, 1; -- EventClass (SP:StmtStarting) Success
EXEC sp_trace_setevent @TraceID, 40, 25, 1; -- EventClass (SP:StmtStarting) IntegerData
EXEC sp_trace_setevent @TraceID, 40, 27, 1; -- EventClass (SP:StmtStarting) EventClass
EXEC sp_trace_setevent @TraceID, 40, 31, 1; -- EventClass (SP:StmtStarting) Error Number
EXEC sp_trace_setevent @TraceID, 40, 34, 1; -- EventClass (SP:StmtStarting) ObjectName
EXEC sp_trace_setevent @TraceID, 40, 49, 1; -- EventClass (SP:StmtStarting) RequestID
EXEC sp_trace_setevent @TraceID, 40, 55, 1; -- EventClass (SP:StmtStarting) IntegerData2

EXEC sp_trace_setevent @TraceID, 41,  1, 1; -- EventClass (SP:StmtCompleted) TextData
EXEC sp_trace_setevent @TraceID, 41,  4, 1; -- EventClass (SP:StmtCompleted) TransactionId
EXEC sp_trace_setevent @TraceID, 41,  9, 1; -- EventClass (SP:StmtCompleted) ClientProcessID
EXEC sp_trace_setevent @TraceID, 41, 10, 1; -- EventClass (SP:StmtCompleted) ApplicationName
EXEC sp_trace_setevent @TraceID, 41, 11, 1; -- EventClass (SP:StmtCompleted) LoginName
EXEC sp_trace_setevent @TraceID, 41, 12, 1; -- EventClass (SP:StmtCompleted) SPID
EXEC sp_trace_setevent @TraceID, 41, 13, 1; -- EventClass (SP:StmtCompleted) ClientProcessID
EXEC sp_trace_setevent @TraceID, 41, 14, 1; -- EventClass (SP:StmtCompleted) StartTime
EXEC sp_trace_setevent @TraceID, 41, 15, 1; -- EventClass (SP:StmtCompleted) EndTime
EXEC sp_trace_setevent @TraceID, 41, 20, 1; -- EventClass (SP:StmtCompleted) Severity
EXEC sp_trace_setevent @TraceID, 41, 23, 1; -- EventClass (SP:StmtCompleted) Success
EXEC sp_trace_setevent @TraceID, 41, 25, 1; -- EventClass (SP:StmtCompleted) IntegerData
EXEC sp_trace_setevent @TraceID, 41, 27, 1; -- EventClass (SP:StmtCompleted) EventClass
EXEC sp_trace_setevent @TraceID, 41, 31, 1; -- EventClass (SP:StmtCompleted) Error Number
EXEC sp_trace_setevent @TraceID, 41, 34, 1; -- EventClass (SP:StmtCompleted) ObjectName
EXEC sp_trace_setevent @TraceID, 41, 49, 1; -- EventClass (SP:StmtCompleted) RequestID
EXEC sp_trace_setevent @TraceID, 41, 55, 1; -- EventClass (SP:StmtCompleted) IntegerData2

-- Step 3: Set a filter for the table CommandOrderParts
EXEC sp_trace_setfilter @TraceID, 55, 0, 6, N'dbo.CommandOrderParts'; -- ObjectName filter

-- Optional: Add a filter for ApplicationName to capture specific applications
EXEC sp_trace_setfilter @TraceID, 10, 0, 6, N'File_App1'; -- Filter for File_App1.dll
EXEC sp_trace_setfilter @TraceID, 10, 1, 6, N'File_App2'; -- Filter for File_App2.dll

-- Step 4: Start the trace
EXEC sp_trace_setstatus @TraceID, 1; -- Start the trace

-- Step 5: Stop the trace
EXEC sp_trace_setstatus @TraceID, 0; -- Stop the trace

执行时运行到步骤4启动追踪,需要停止时再执行步骤5。
自身环境为SQL Server 2017 (RTM-CU31-GDR) (KB5029376),参考对应版本的官方文档获取事件定义,通过文档页面标题截图确认版本匹配。


死锁敏感性补充

应用对死锁敏感,不到6个月已出现213次死锁相关异常,示例如下:

2024-10-28 12:53:31.5199 | Error | App1.RaiseConnectionFailed | Telerik.OpenAccess.RT.sql.SQLException: Transaction (Process ID 76) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. ---> System.Data.SqlClient.SqlException: Transaction (Process ID 76) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlDataReader.TryHasMoreRows(Boolean& moreRows)
   at System.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean& more)
   at System.Data.SqlClient.SqlDataReader.Read()
   at OpenAccessRuntime.Intellitrace.Read(DbDataReader reader, String id)
   at Telerik.OpenAccess.Runtime.Logging.LoggingDbDataReader.Read()
   at Telerik.OpenAccess.RT.Adonet2Generic.Impl.ResultSetImp.next()
   --- End of inner exception stack trace ---
   at Telerik.OpenAccess.RT.Adonet2Generic.Impl.ResultSetImp.next()
   at OpenAccessRuntime.Relational.fetch.FetchResultImp.rsNext()
   at OpenAccessRuntime.Relational.fetch.FetchResultImp.hasNext()  

内容的提问来源于stack exchange,提问作者Dominique

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 22:57:01