上一篇中我们可以看出Fill方法最后都调用FillFromCommand和FillFromReader方法。 那我们接着探讨FillFromCommand方法 private int FillFromCommand(object data, int startRecord, int maxRecords, string srcTable, IDbCommand command, CommandBehavior behavior) { IDbConnection connection1 = DbDataAdapter.GetConnection(command, "Fill");//返回connection ConnectionState state1 = ConnectionState.Open; if (MissingSchemaAction.AddWithKey == base.MissingSchemaAction)
//添加必需的列和主键信息以完成架构。
{ behavior |= CommandBehavior.KeyInfo; } int num1 = 0; try { try { DbDataAdapter.QuietOpen(connection1, out state1);//打开连接 using (IDataReader reader1 = command.ExecuteReader(behavior | CommandBehavior.SequentialAccess))//读取数据 { if (data is DataTable) { num1 = this.Fill((DataTable) data, reader1);//这个方法我们已经
//说过它最后调用FillFromReader(dataTable, null, dataReader, 0, 0, null, null);
} else { num1 = this.Fill((DataSet) data, srcTable, reader1, startRecord, maxRecords);
//这个方法最后调用 return this.FillFromReader(dataSet, srcTable, dataReader,
//startRecord, maxRecords, null, null);
} } } finally { DbDataAdapter.QuietClose(connection1, state1);//关闭连接 } } catch { throw; } return num1; } 这是就不难看出FillFromCommand其实也是在调用了FillFromReader,也就是说Fill方法的所有操作将由FillFromReader方法来完成。
看看FillFromReader方法: internal int FillFromReader(object data, string srcTable, IDataReader dataReader, int startRecord, int maxRecords, DataColumn parentChapterColumn, object parentChapterValue) { int num1 = 0; int num2 = 0;//schemaCount Label_0004: if (0 < dataReader.FieldCount) { SchemaMapping mapping1 = this.FillSchemaMappingTry(data, srcTable, dataReader, num2, parentChapterColumn, parentChapterValue);//创建结构映射 num2++; if (((mapping1 != null) && (mapping1.DataValues != null)) && (mapping1.DataTable != null)) { try { mapping1.DataTable.BeginLoadData();//加载数据时关闭通知、索引维护和约束 try { if ((1 == num2) && ((0 < startRecord) || (0 < maxRecords))) { num1 = this.FillLoadDataRowChunk(mapping1, startRecord, maxRecords);//填充从
//startRecord开始的maxRecords条记录,并返回记录个数 } else { int num3 = this.FillLoadDataRow(mapping1);//填充数据 if (1 == num2) { num1 = num3; } } } finally { mapping1.DataTable.EndLoadData();//数据加载后打开通知、索引维护和约束。 } } catch { throw; } } } if (!this.FillNextResult(dataReader))//判断dataReader中是否还有记录 { return num1; } goto Label_0004; } 其实到这里我们已经对fill有个总体了解,首先不管fill重载多少次它都是最后调用FillFromReader方法,在FillFromReader中先创建结构映射,然后填充数据。 接着看看结构影射,这个很复杂,请朋友们多多指教。 //结构影射 private SchemaMapping FillSchemaMappingTry(object data, string srcTable, IDataReader dataReader, int schemaCount, DataColumn parentChapterColumn, object parentChapterValue) { SchemaMapping mapping1 = null; if (this.hasFillErrorHandler) { try { mapping1 = this.FillSchemaMapping(data, srcTable, dataReader, schemaCount, parentChapterColumn, parentChapterValue); } catch (Exception exception1) { this.FillErrorHandler(exception1, null, null); } } else { mapping1 = this.FillSchemaMapping(data, srcTable, dataReader, schemaCount, parentChapterColumn, parentChapterValue); } return mapping1; } //FillSchemaMapping private SchemaMapping FillSchemaMapping(object data, string srcTable, IDataReader dataReader, int schemaCount, DataColumn parentChapterColumn, object parentChapterValue) { SchemaMapping mapping1 = new SchemaMapping(this, dataReader, MissingSchemaAction.AddWithKey == base.MissingSchemaAction);//创建SchemaMapping实例 //成员名称 说明 //MissingSchemaAction: // Add 添加必需的列以完成架构。 // AddWithKey 添加必需的列和主键信息以完成架构。有关如何将主键信息添加到 DataTable 的更多信息,请参见 FillSchema。 // Error 如果缺少指定的列映射,则生成 InvalidOperationException。 // Ignore 忽略额外列。
string text1 = null; if (data is DataTable) { mapping1.DataTable = (DataTable) data; } else { mapping1.DataSet = (DataSet) data; text1 = DbDataAdapter.GetSourceTableName(srcTable, schemaCount);//DataSet中要创建表的名称 /** *internal static string GetSourceTableName(string srcTable, int index) *{ * if (index == 0) * { * return srcTable; *} * return (srcTable + index.ToString()); * } **/
} mapping1.SetupSchema(SchemaType.Mapped, text1, true, parentChapterColumn, parentChapterValue);// /* * * public enum SchemaType *{ * // Fields * Mapped = 2, 将任何现有的表映射应用到传入架构,用转换的架构配置 DataSet。 * Source = 1 忽略 DataAdapter 上的任何表映射。使用传入架构配置 DataSet,而不应用任何转换。 * } **/
return mapping1; } //SchemaMapping internal SchemaMapping(DbDataAdapter adapter, IDataReader dataReader, bool keyInfo) { this.adapter = adapter; this.dataReader = dataReader; if (keyInfo)//如果必须添加列和主键,就用dataReader的GetSchemaTable()返回一个DataTable { this.schemaTable = dataReader.GetSchemaTable();//返回一个 DataTable,它描述 SqlDataReader 的列元数据。可以查看msdn
} } //SetupSchema 创建 internal void SetupSchema(SchemaType schemaType, string sourceTableName, bool gettingData, DataColumn parentChapterColumn, object parentChapterValue) { MissingMappingAction action1; MissingSchemaAction action2; if (SchemaType.Mapped == schemaType) { action1 = this.adapter.MissingMappingAction;//确定传入数据没有匹配的表或列时需要执行的操作 action2 = this.adapter.MissingSchemaAction;//确定现有 DataSet 架构与传入数据不匹配时需要执行的操作。 if (!ADP.IsEmpty(sourceTableName)) { this.tableMapping = this.adapter.GetTableMappingBySchemaAction(sourceTableName, sourceTableName, action1);//创建源表和 DataTable 之间的主映射。 goto Label_016D; } if (this.dataTable == null) { goto Label_016D; } int num1 = this.adapter.IndexOfDataSetTable(this.dataTable.TableName); if (-1 != num1) { this.tableMapping = this.adapter.TableMappings[num1]; goto Label_016D; } switch (action1) { case MissingMappingAction.Passthrough://创建源列或源表,并使用其原始名称将其添加到 DataSet。 { this.tableMapping = new DataTableMapping(this.dataTable.TableName, this.dataTable.TableName); goto Label_016D; } case MissingMappingAction.Ignore://忽略没有映射的列或表。 { this.tableMapping = null; goto Label_016D; } case MissingMappingAction.Error://缺少指定的列映射,则生成 InvalidOperationException { throw ADP.MissingTableMappingDestination(this.dataTable.TableName); } } throw ADP.InvalidMappingAction((int) action1); } if (SchemaType.Source != schemaType) { throw ADP.InvalidSchemaType((int) schemaType); } action1 = MissingMappingAction.Passthrough; action2 = MissingSchemaAction.Add; if (!ADP.IsEmpty(sourceTableName)) { this.tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction(null, sourceTableName, sourceTableName, action1); } else if (this.dataTable != null) { int num2 = this.adapter.IndexOfDataSetTable(this.dataTable.TableName); if (-1 != num2) { this.tableMapping = this.adapter.TableMappings[num2]; } else { this.tableMapping = new DataTableMapping(this.dataTable.TableName, this.dataTable.TableName);////创建源表和 DataTable 之间的主映射。 } } Label_016D: if (this.tableMapping != null) { if (this.dataTable == null) { this.dataTable = this.tableMapping.GetDataTableBySchemaAction(this.dataSet, action2);使用action2的 值获取DataSet的当前 DataTable。可以查看msdn if (this.dataTable == null) { return; } } if (this.schemaTable == null) { this.SetupSchemaWithoutKeyInfo(action1, action2, gettingData, parentChapterColumn, parentChapterValue); } else { this.SetupSchemaWithKeyInfo(action1, action2, gettingData, parentChapterColumn, parentChapterValue); } } } //FillLoadDataRowChunk private int FillLoadDataRowChunk(SchemaMapping mapping, int startRecord, int maxRecords) { IDataReader reader1 = mapping.DataReader; while (0 < startRecord) //把DataReader调整到读startRecord记录的位置 { //如果DataReader的总的记录数小于startRecord,就返回0 if (!reader1.Read()) //其实在这里也可以看出要在DataReader中定位,只有去边历DataReader { //到这里我们也可以明白fill方法其实也是用DataReader一条条读出来的 return 0; } startRecord--; } int num1 = 0; if (0 >= maxRecords) { goto Label_0062; } bool flag1 = base.AcceptChangesDuringFill;//指示在Fill操作过程中,在将 AcceptChanges 添加到 DataTable 之后是否针对 DataRow 调用它。可以在msdn中的DataAdapter 类中查看 goto Label_0054; Label_002B: try { mapping.LoadDataRow(this.hasFillErrorHandler, flag1);//装载数据 num1++; } catch (Exception exception1) { this.FillErrorHandler(exception1, mapping.DataTable, mapping.DataValues); } Label_0054: if (num1 >= maxRecords)//如果载入的记录数已经满足条件,就退出,否则继续 { goto Label_006A; } if (reader1.Read())//继续读取数据 { goto Label_002B; } goto Label_006A; Label_0062: num1 = this.FillLoadDataRow(mapping); Label_006A: return num1; } 到这里fill方法大概就完了,其实看来fill方法就是首先创建映射,然后在用datareader把数据填充进来.其中我忽略了好多东西比如它的异常处理,还有好多细节,请各位朋友多多指教,在这里列出来也是和各位朋友探讨。

|