SqlDataAdapter中的Fill方法(2)

类别:.NET开发 点击:0 评论:0 推荐:

上一篇中我们可以看出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把数据填充进来.其中我忽略了好多东西比如它的异常处理,还有好多细节,请各位朋友多多指教,在这里列出来也是和各位朋友探讨。

本文地址:http://com.8s8s.com/it/it44063.htm