DataTable 'Table' 已经属于这个数据集 - 在新的数据集上?
DataTable 'Table' already belongs to this DataSet - on a new DataSet?
我有一个执行 SQL 查询的函数和 return 查询结果的通用数据集。这个功能已经在许多应用程序中工作多年,但今天我得到了一个特定的查询
"Error executing [select top (1) RecordId, SourceCID, SourceID,
CaseID, DisposeRequestedDate, DisposeRequestedBy, DisposeApprovedDate,
DisposeApprovedBy from
mycatalog.dbo.CASD_RetentionManagementDisposalApprovedQueue order by
DisposeApprovedDate, RecordID;] A DataTable named 'Table' already
belongs to this DataSet."
函数是
public static DataSet ExecSQLQuery(string sqlQuery)
{
mDataSet = new DataSet();
... // setup, but NO references to mDataSet
try {
... // establish, open connection as "conn"
mDataAdapter = new SqlDataAdapter(new SqlCommand(sqlQuery, conn));
mDataAdapter.Fill(mDataSet);
} catch (Exception ex) {
// this traps "A DataTable named 'Table' already belongs to this DataSet."
Log("Error executing [" + sql + "]" + ex.message);
}
finally {
if (conn != null)
{
if (conn.State == ConnectionState.Open)
conn.Close();
conn.Dispose();
}
}
return mDataSet;
}
调用过程基本上是:
public static ProcessResult ProcessDestructQueue()
{
// maxRecords is a configuration setting, currently set to 1
string sql = "select top (" + maxRecords.ToString() + ") RecordId, SourceCID, SourceID, CaseID, DisposeRequestedDate, DisposeRequestedBy, DisposeApprovedDate, DisposeApprovedBy " +
" from mycatalog.dbo.CASD_RetentionManagementDisposalApprovedQueue " +
" order by DisposeApprovedDate, RecordID;";
DataSet ds = null;
try {
sWhere = "exec query [ " + sql + " ]";
ds = SQLUtility.ExecSQLQuery(sql);
if (!SQLUtility.IsValidDataSet(ds))
{
if (!SQLUtility.IsValidButEmptyDataSet(ds))
throw new Exception("Failed to get a valid data set with [ " + sql + " ]");
//
// no records to process
//
return ProcessResult.NOFILESTOPROCESS;
}
}
catch (...) { ... }
finally {
if (ds != null)
ds.Dispose();
}
...
}
当我的配置参数设置为 1 (Select top (1) ...) 时,出现错误。当设置为2时,(Select top(2) ...),不会出现该错误。
“Select top (1)...”有什么独特之处还是我做错了什么?
顺便说一句 - table 当前为空,因此前 1 和前 2 都不应该 return 任何行。
根据要求 - IsValidDataSet 和 IsValidButEmptyDataSet 方法:
public static bool IsValidDataSet(DataSet ds)
{
if (ds != null)
if (ds.Tables.Count > 0)
if (ds.Tables[0] != null)
if (ds.Tables[0].Rows.Count > 0)
if (ds.Tables[0].Rows[0] != null)
if (ds.Tables[0].Rows[0].ItemArray.Length > 0)
return true;
return false;
}
public static bool IsValidButEmptyDataSet(DataSet ds)
{
if (ds == null || ds.Tables.Count == 0 || ds.Tables[0].Rows.Count == 0)
return true;
return false;
}
根据要求 - 来自错误的堆栈跟踪:
堆栈跟踪:
在 System.Data.DataTableCollection.RegisterName(字符串名称,字符串 tbNamespace)
在 System.Data.DataTableCollection.BaseAdd(数据表 table)
在 System.Data.DataTableCollection.Add(数据表 table)
在 System.Data.ProviderBase.SchemaMapping.SetupSchemaWithoutKeyInfo(MissingMappingAction mappingAction、MissingSchemaAction schemaAction、布尔值 gettingData、DataColumn parentChapterColumn、对象 chapterValue)
在 System.Data.ProviderBase.SchemaMapping..ctor(DataAdapter 适配器、DataSet 数据集、DataTable 数据table、DataReaderContainer dataReader、Boolean keyInfo、SchemaType schemaType、String sourceTableName、Boolean gettingData、DataColumn parentChapterColumn、Object parentChapterValue)
在 System.Data.Common.DataAdapter.FillMappingInternal(DataSet 数据集、DataTable 数据table、String srcTable、DataReaderContainer dataReader、Int32 schemaCount、DataColumn parentChapterColumn、Object parentChapterValue)
在 System.Data.Common.DataAdapter.FillMapping(DataSet 数据集、DataTable 数据table、String srcTable、DataReaderContainer dataReader、Int32 schemaCount、DataColumn parentChapterColumn、Object parentChapterValue)
在 System.Data.Common.DataAdapter.FillFromReader(DataSet 数据集、DataTable 数据table、String srcTable、DataReaderContainer dataReader、Int32 startRecord、Int32 maxRecords、DataColumn parentChapterColumn、Object parentChapterValue)
在 System.Data.Common.DataAdapter.Fill(DataSet 数据集、字符串 srcTable、IDataReader dataReader、Int32 startRecord、Int32 maxRecords)
在 System.Data.Common.DbDataAdapter.FillInternal(DataSet 数据集、DataTable[] 数据tables、Int32 startRecord、Int32 maxRecords、String srcTable、IDbCommand 命令、CommandBehavior 行为)
在 System.Data.Common.DbDataAdapter.Fill(DataSet 数据集、Int32 startRecord、Int32 maxRecords、String srcTable、IDbCommand 命令、CommandBehavior 行为)
在 System.Data.Common.DbDataAdapter.Fill(数据集数据集)
在 SQLUtility.ExecSQLQuery(字符串 sqlQuery,布尔值 ignoreError)
我相信我已经弄清楚发生了什么。
我的 ExecSQLQuery 方法不是线程安全的(它是一个 public 静态方法),但我有两个独立的计时器 运行。如果计时器 2 在计时器 1 处理序列当前正在该方法内执行时触发,则第二个可以结束调用同一过程。当计时器 2 进程终止时,第一个代码恢复,但局部变量现在已经加载,导致“'Table' 已经属于数据集”错误。
我添加了很多诊断代码,发现这只是在两个定时器触发的大量执行之后才会发生。
我将添加一个信号量以防止一个进程在另一个进程已在执行时执行。
我有一个执行 SQL 查询的函数和 return 查询结果的通用数据集。这个功能已经在许多应用程序中工作多年,但今天我得到了一个特定的查询
"Error executing [select top (1) RecordId, SourceCID, SourceID, CaseID, DisposeRequestedDate, DisposeRequestedBy, DisposeApprovedDate, DisposeApprovedBy from mycatalog.dbo.CASD_RetentionManagementDisposalApprovedQueue order by DisposeApprovedDate, RecordID;] A DataTable named 'Table' already belongs to this DataSet."
函数是
public static DataSet ExecSQLQuery(string sqlQuery)
{
mDataSet = new DataSet();
... // setup, but NO references to mDataSet
try {
... // establish, open connection as "conn"
mDataAdapter = new SqlDataAdapter(new SqlCommand(sqlQuery, conn));
mDataAdapter.Fill(mDataSet);
} catch (Exception ex) {
// this traps "A DataTable named 'Table' already belongs to this DataSet."
Log("Error executing [" + sql + "]" + ex.message);
}
finally {
if (conn != null)
{
if (conn.State == ConnectionState.Open)
conn.Close();
conn.Dispose();
}
}
return mDataSet;
}
调用过程基本上是:
public static ProcessResult ProcessDestructQueue()
{
// maxRecords is a configuration setting, currently set to 1
string sql = "select top (" + maxRecords.ToString() + ") RecordId, SourceCID, SourceID, CaseID, DisposeRequestedDate, DisposeRequestedBy, DisposeApprovedDate, DisposeApprovedBy " +
" from mycatalog.dbo.CASD_RetentionManagementDisposalApprovedQueue " +
" order by DisposeApprovedDate, RecordID;";
DataSet ds = null;
try {
sWhere = "exec query [ " + sql + " ]";
ds = SQLUtility.ExecSQLQuery(sql);
if (!SQLUtility.IsValidDataSet(ds))
{
if (!SQLUtility.IsValidButEmptyDataSet(ds))
throw new Exception("Failed to get a valid data set with [ " + sql + " ]");
//
// no records to process
//
return ProcessResult.NOFILESTOPROCESS;
}
}
catch (...) { ... }
finally {
if (ds != null)
ds.Dispose();
}
...
}
当我的配置参数设置为 1 (Select top (1) ...) 时,出现错误。当设置为2时,(Select top(2) ...),不会出现该错误。 “Select top (1)...”有什么独特之处还是我做错了什么? 顺便说一句 - table 当前为空,因此前 1 和前 2 都不应该 return 任何行。
根据要求 - IsValidDataSet 和 IsValidButEmptyDataSet 方法:
public static bool IsValidDataSet(DataSet ds)
{
if (ds != null)
if (ds.Tables.Count > 0)
if (ds.Tables[0] != null)
if (ds.Tables[0].Rows.Count > 0)
if (ds.Tables[0].Rows[0] != null)
if (ds.Tables[0].Rows[0].ItemArray.Length > 0)
return true;
return false;
}
public static bool IsValidButEmptyDataSet(DataSet ds)
{
if (ds == null || ds.Tables.Count == 0 || ds.Tables[0].Rows.Count == 0)
return true;
return false;
}
根据要求 - 来自错误的堆栈跟踪: 堆栈跟踪: 在 System.Data.DataTableCollection.RegisterName(字符串名称,字符串 tbNamespace) 在 System.Data.DataTableCollection.BaseAdd(数据表 table) 在 System.Data.DataTableCollection.Add(数据表 table) 在 System.Data.ProviderBase.SchemaMapping.SetupSchemaWithoutKeyInfo(MissingMappingAction mappingAction、MissingSchemaAction schemaAction、布尔值 gettingData、DataColumn parentChapterColumn、对象 chapterValue) 在 System.Data.ProviderBase.SchemaMapping..ctor(DataAdapter 适配器、DataSet 数据集、DataTable 数据table、DataReaderContainer dataReader、Boolean keyInfo、SchemaType schemaType、String sourceTableName、Boolean gettingData、DataColumn parentChapterColumn、Object parentChapterValue) 在 System.Data.Common.DataAdapter.FillMappingInternal(DataSet 数据集、DataTable 数据table、String srcTable、DataReaderContainer dataReader、Int32 schemaCount、DataColumn parentChapterColumn、Object parentChapterValue) 在 System.Data.Common.DataAdapter.FillMapping(DataSet 数据集、DataTable 数据table、String srcTable、DataReaderContainer dataReader、Int32 schemaCount、DataColumn parentChapterColumn、Object parentChapterValue) 在 System.Data.Common.DataAdapter.FillFromReader(DataSet 数据集、DataTable 数据table、String srcTable、DataReaderContainer dataReader、Int32 startRecord、Int32 maxRecords、DataColumn parentChapterColumn、Object parentChapterValue) 在 System.Data.Common.DataAdapter.Fill(DataSet 数据集、字符串 srcTable、IDataReader dataReader、Int32 startRecord、Int32 maxRecords) 在 System.Data.Common.DbDataAdapter.FillInternal(DataSet 数据集、DataTable[] 数据tables、Int32 startRecord、Int32 maxRecords、String srcTable、IDbCommand 命令、CommandBehavior 行为) 在 System.Data.Common.DbDataAdapter.Fill(DataSet 数据集、Int32 startRecord、Int32 maxRecords、String srcTable、IDbCommand 命令、CommandBehavior 行为) 在 System.Data.Common.DbDataAdapter.Fill(数据集数据集) 在 SQLUtility.ExecSQLQuery(字符串 sqlQuery,布尔值 ignoreError)
我相信我已经弄清楚发生了什么。
我的 ExecSQLQuery 方法不是线程安全的(它是一个 public 静态方法),但我有两个独立的计时器 运行。如果计时器 2 在计时器 1 处理序列当前正在该方法内执行时触发,则第二个可以结束调用同一过程。当计时器 2 进程终止时,第一个代码恢复,但局部变量现在已经加载,导致“'Table' 已经属于数据集”错误。
我添加了很多诊断代码,发现这只是在两个定时器触发的大量执行之后才会发生。
我将添加一个信号量以防止一个进程在另一个进程已在执行时执行。