ASP.NET2.0中利用C#实现DBF文件向MDB文件的转换


1 前言

   目前,Access+ASP.NET模式广泛应用于中小型网站的构建,MDB文件是Access数据库文件,是该模式下网站的数据源。DBF文件是微软桌面数据库软件FoxPro的数据库文件,以其简单易学、操作方便等优点仍然广泛应用于高校的招生、学籍、就业等教学管理环节中,如上级部门下达的数据库文件、高校给上级部门的上报数据文件仍然是DBF文件。由此可见,基于MDB文件的教学管理系统在数据源的格式方面就与日常报表所用的DBF文件存存不一致性,要解决这个问题通常可借助于第三软件(如Microsoft Office系统提供的Access组件或专用的共享软件)来完成文件格式的转换,即数据的转换具有一定的依赖性。作为一个应用系统,应尽量减少这种依赖性,让用户在应用中直接使用DBF文件,因而要求我们开发的应用系统能自动地完成DBF文件向MDB文件的转换,这就是本文要解决的问题。

  2  工作原理

   ADO.NET是.NET平台上数据库访问技术之一,该技术提供对数据库读写、显示等功能组件,如DataReader、DataAdapter、DataSet等,借助于DataReader对DBF文件实现数据以行记录方式读出,以DataAdapter作为DataSet与数据源(MDB文件)的数据适匹器,调用DataAdapter的Fill方法填充DataSet得到一个DataTable(数据表),通过调用DataAdapter的Update方法将变化了的DataSet数据更新源数据(MDB文件),从而实现DBF向MDB文件的转换。

  3  实现过程

   实现的过程可分为三个主要步骤:创建MDB文件→在MDB文件中创建数据表(即创建表结构)→往数据表添加数据。在这三个主要步骤中均需要使用ADO.NET技术连接DBF文
件,ASP.NET下利用C#连接DBF的关键代码可表示为:

        OdbcConnection conn = new OdbcConnection();
        string connStr = @"Driver={Microsoft Visual FoxPro Driver};SourceType=DBF;SourceDB=" +
        dbfFileName + ";Exclusive=No;NULL=NO;Collate=Machine;BACKGROUNDFETCH=NO;DELETED=NO";
        sqlString = "select * from " + dbfFileName;
        conn.ConnectionString = connStr;
        conn.Open();

   其中dbfFileName表示待连接的DBF数据库(含路径和扩展名),实际应用时以上代码可封装成一个方法,将方法类型定义为OdbcConnection,即方法返回值为OdbcConnection类型,方法的形参为string类型,代表待连接的DBF数据库文件名。下面为方法的定义与调用代码:

   //定义连接DBF数据库方法
private OdbcConnection OpenDbfDatabase(string databaseFileName)
{
       string dbfFileName = databaseFileName;
   //此处为连接DBF数据库的具体代码
        return conn;
}
//调用方法
OdbcConnection conn = OpenDbfDatabase(dbfFilePathAndFileName); //打开DBF数据表并回传conn

   其中dbfFilePathAndFileName为string类型变量,是从网页打开文件选择框中取得的DBF文件名(含路径和扩展名)。

  3.1 创建MDB文件即创建Access数据库

   .NET2.0框架下动态创建Access数据库需要在应用系统中添加引用“Microsoft ADD Ext.2.8 For DDL and Security”,如图 1所示:

  图 1

   然后通过使用ADOX命名空间下CatalogClass类的Create方法实现[1],实现的关键代码为:

ADOX.CatalogClass myCatalogClass = new ADOX.CatalogClass();
myCatalogClass.Create("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + mdbFileName + ";");

   其中变量mdbFileName表示待创建的Access数据库文件名(含路径和扩展名)。

  3.2 创建Access数据表

   Access数据表与DBF数据库一样都是属于二维关系数据库,即以每个字段为一列、每行为一条记录的数据集合。然而它们的字段类型并不是一一对应关系,因此为了保证转换后数据的完整性必须先明白二者的字段类型的对应关系。表格 1是它们的字段类型对应表:

  表格 1

  DBF文件

  MDB文件

  字段类型

  字段类型

  对应System命名空间的字符表示

  字符型

  文本

  System.String

  货币型

  数字

  System.Decimal

  数值型

  数字

  System.Decimal

  浮动型

  数字

  System.Decimal

  日期型

  日期/时间

  System.DateTime

  日期时间型

  日期/时间

  System.DateTime

  双精度型

  数字

  System.Double

  整型

  数字

  System.Int32

  逻辑型

  是/否

  System.Boolean

  备注型

  文本

  System.String

  通用型

  二进制

  System.Byte[]

  字符型(二进制)

  二进制

  System.Byte[]

  备注型(二进制)

  二进制

  System.Byte[]

   在Access数据库中动态创建数据表的过程实际上就是创建数据库的结构,根据表格 1所提供的它们二者字段类型的对应关系,通过ADO.NET技术首先连接DBF文件,再利用ADO.NET Framework数据提供程序的DataReader对象即可取得DBF文件各字段属性(字段名称、类型等)。

   .NET2.0框架下动态创建Access数据表也需要在应用系统中添加引用“Microsoft ADD Ext.2.8 For DDL and Security”,然后使用ADOX命名空间下TableClass类中的相关方法和属性实现[1]。实现的关键代码如下:

        ADOX.TableClass tmpTable = new ADOX.TableClass();
        tmpTable.ParentCatalog = myCatalogClass;
        tmpTable.Name = "MyTable";         //待创建的数据表名
        conn.Open();                      //连接DBF数据库
        OdbcCommand myDbfCommand = new OdbcCommand(sqlString, conn);
        OdbcDataReader myDbfReader = myDbfCommand.ExecuteReader();
        int DbfFieldCount = myDbfReader.FieldCount;
        string myTableFieldName;         //待创建的数据表字段名称
        string myTableFieldType;         //待创建的数据表字段类型
        for (int i = 0; i < DbfFieldCount; i++)
        {
            ADOX.ColumnClass col = new ADOX.ColumnClass();
            col.ParentCatalog = myCatalogClass;
            col.Properties["Jet OLEDB:Allow Zero Length"].Value = false;
            myTableFieldName = myDbfReader.GetName(i).ToString(); 
             //获取数据表字段名称
            col.Name = myTableFieldName;
             myTableFieldType = myDbfReader.GetFieldType(i).ToString();
             //获取数据表字段类型       
            switch (myTableFieldType)
            {
                case "System.String":
                    {
                        tmpTable.Columns.Append(col, ADOX.DataTypeEnum.adVarChar, 255);
                        break;
                    }
                case "System.Decimal":
                    {
                        col.Type = ADOX.DataTypeEnum.adDouble;
                        tmpTable.Columns.Append(col, ADOX.DataTypeEnum.adDouble, 20);
                        break;
                    }
                case "System.DateTime":
                    {
                        col.Type = ADOX.DataTypeEnum.adDate;
                        tmpTable.Columns.Append(col, ADOX.DataTypeEnum.adDate, 10);
                        break;
                    }
                case "System.Double":
                    {
                        col.Type = ADOX.DataTypeEnum.adDouble;
                        tmpTable.Columns.Append(col, ADOX.DataTypeEnum.adDouble, 20);
                        break;
                    }
                case "System.Int32":
                    {
                        col.Type = ADOX.DataTypeEnum.adSingle;
                        tmpTable.Columns.Append(col, ADOX.DataTypeEnum.adSingle, 10);
                        break;
                    }
                case "System.Boolean":
                    {
                        col.Type = ADOX.DataTypeEnum.adBoolean;
                        tmpTable.Columns.Append(col, ADOX.DataTypeEnum.adBoolean, 2);
                        break;
                    }
                case "System.Byte[]":
                    {
                        col.Type = ADOX.DataTypeEnum.adBinary;
                        tmpTable.Columns.Append(col, ADOX.DataTypeEnum.adBinary, 255);
                        break;
                    }
                default:
                    break;                }
        }      
        myCatalogClass.Tables.Append(tmpTable);
        System.Runtime.InteropServices.Marshal.ReleaseComObject(tmpTable);
        System.Runtime.InteropServices.Marshal.ReleaseComObject(myCatalogClass);
        tmpTable = null;
        myCatalogClass = null;
        conn.Close();
        //GC.WaitForPendingFinalizers();
        //GC.Collect();

  3.3 给数据表以行为单位追加数据

   这一步骤是整个转换工作的核心,实际上就是每次从DBF文件读出一行记录后将数据以行为单位插入到Access表中。那么是如何来完成数据的读出与插入呢?

  3.3.1 .NET平台中数据源更新机制

   ADO.NET是.NET框架的重要组成部分,它为应用程序提供数据访问的能力,如为运行能用于访问关系型数据库系统,为运行SQL查询、存储过程、操作XML数据提供所需的工具;DataSet和.NET Framework数据提供程序是组成ADO.NET的二个核心组件,DataSet是一组驻留于内存的数据集,它具有类似关系数据库的结构,主要由数据表(DataTable)和关系组成,.NET Framework数据提供程序是一组包含Connection、Command、DataReader、DataAdapter对象在内的组件,表格 2列出了这四个对象的主要功能:

  表格 2

  对象

  说明

  Connection

  与指定的数据源建立连接

  Command

  对数据源执行命令操作

  DataReader

  从数据源中读取只进且只读的数据流

  DataAdapter

  用数据源填充DataSet并解析更新

   从表中可以看出DataAdapter充当了数据源和DataSet的桥梁,它有二个作用:①从数据源将数据读入数据集DataSet②从数据集将已更改数据(插入记录、更新数据、删除记录)写回数据源。每一个DataAdapter对象都有四个属性,如表格 3下表:

  表格 3

  属性

  说明

  SelectCommand

  引用SQL语句从数据存储区检索行

  InsertCommand

  引用命令向数据存储区插入行

  UpdateCommand

  引用命令修改数据存储区中的行

  DeleteCommand

  引用命令从数据存储区删除行

   DataAdapter有二个常用方法:Fill方法和Update方法,Fill方法用于使用DataAdapter的SelectCommand的结果来填充DataSet;Update方法可以将DataSet中的数据更新回原数据源,调用Update方法时,DataAdapter将先分析已做出的更改(数据行DataRow数据发生变化),然后使用InsertCommand(插入操作)、UpdateCommand(更新操作)、DeleteCommand(删除操作)来处理该更动,所以在使用Update方法前必须显式设置这些命令。

   .NET平台中利用ADO.NET技术将变化了的数据回写到数据库的相应数据表中的方法有二个:①通过创建一个Command对象执行特定的SQL语句来实现;②使用DataAdapter对象中的更新逻辑实现。本文采用的是第二种方法,在这四个属性中只有SelectCommand和InsertCommand属性与数据的插入有关,下面以具体的代码来说明转换的实现过程,代码已封装成一个方法。

  3.3.2 给Access数据表追加数据完成DBF向MDB文件的转换的方法(关键代码)

   //定义往Access数据表追加数据的方法,参数mdbFileName代表Access数据库文件名
    private void AddDataToMdbTable(OdbcConnection conn,string mdbFileName)
    {
        string myTableFieldName;
        string myTableFieldName2;
        string myTableFieldType;
        string fieldString1 = "";
        string fieldString2 = "";
        OleDbType tmpType = System.Data.OleDb.OleDbType.VarChar;
        int myTableFieldSize = 100;
        string connectionString = @"Provider = Microsoft.Jet.OLEDB.4.0;";
        connectionString = connectionString + " Data Source=" + mdbFileName;
        OleDbConnection myConnection = new OleDbConnection();
        myConnection.ConnectionString = connectionString;
        myConnection.Open();  //连接MDB数据库
 
        string sqlMdbString = "select * from myTable";
        OleDbCommand myCommand = new OleDbCommand(sqlMdbString, myConnection);
        OleDbDataAdapter mdbDa = new OleDbDataAdapter(sqlMdbString, myConnection);
        OleDbCommand myInsertCommand = new OleDbCommand();
     
        myInsertCommand.Connection = myConnection;
 
        conn.Open();  //连接待转换的DBF数据库
       
        OdbcCommand myDbfCommand = new OdbcCommand(sqlString, conn);
        OdbcDataReader myDbfReader = myDbfCommand.ExecuteReader();
        int DbfFieldCount = myDbfReader.FieldCount;
 
        for (int i = 0; i < DbfFieldCount; i++)
        {
            myTableFieldName = myDbfReader.GetName(i).ToString(); // 获取DBF文件字段名称
            myTableFieldName2 = "@" + myTableFieldName;  //形成与DBF文件相同的字段名称,字符‘@’不能少
            fieldString1 += myTableFieldName + ",";
            fieldString2 += "@" + myTableFieldName + ",";
            myTableFieldType = myDbfReader.GetFieldType(i).ToString();   //获取字段类型
 
            switch (myTableFieldType)
            {
                case "System.String":
                    {
                        tmpType = System.Data.OleDb.OleDbType.VarChar;
                        myTableFieldSize = 100;
                        break;
                    }
                case "System.Decimal":
                    {
                        tmpType = System.Data.OleDb.OleDbType.Decimal;
                        myTableFieldSize = 10;
                        break;
                    }
                case "System.DateTime":
                    {
                        tmpType = System.Data.OleDb.OleDbType.Date;
                        myTableFieldSize = 12;
                        break;
                    }
                case "System.Double":
                    {
                        tmpType = System.Data.OleDb.OleDbType.Double;
                        myTableFieldSize = 8;
                        break;
                    }
                case "System.Int32":
                    {
                        tmpType = System.Data.OleDb.OleDbType.Integer;
                        myTableFieldSize = 4;
                        break;
                    }
                case "System.Boolean":
                    {
                        tmpType = System.Data.OleDb.OleDbType.Boolean;
                        myTableFieldSize = 1;
                        break;
                    }
            }
            myInsertCommand.Parameters.Add(new OleDbParameter(myTableFieldName2, tmpType, myTableFieldSize, myTableFieldName));
 
        }
        fieldString1 = "INSERT INTO myTable(" + fieldString1 + ")";
        fieldString1 = fieldString1.Remove(fieldString1.LastIndexOf(","), 1);
        fieldString2 = "VALUES(" + fieldString2 + ")";
        fieldString2 = fieldString2.Remove(fieldString2.LastIndexOf(","), 1);
        string fieldString = fieldString1 + " " + fieldString2;
 
        myInsertCommand.CommandText = fieldString;
      
        while (myDbfReader.Read())
        {
            OleDbDataAdapter myAdapter = new OleDbDataAdapter();
            myAdapter.SelectCommand = myCommand;
            myAdapter.InsertCommand = myInsertCommand;
            DataSet newTableDs = new DataSet();
            myAdapter.Fill(newTableDs);
            DataTable newTable = newTableDs.Tables[0];
            DataRow NewMyRow = newTable.NewRow();
 
            for (int i = 0; i < DbfFieldCount; i++)
            {
                string tmpFieldName = myDbfReader.GetName(i).ToString();
                tmpFieldName = tmpFieldName.Trim();
                NewMyRow[tmpFieldName] = myDbfReader[i];
            }
            newTable.Rows.Add(NewMyRow);
            myAdapter.Update(newTableDs);
            newTableDs.Tables[0].AcceptChanges();
            myAdapter.Dispose();
            newTableDs.Clear();
            newTableDs.Dispose();
        }
        myDbfReader.Close();
        conn.Close();
        myConnection.Close();
       
        myConnection.Open();
        string tmpString = "select * from myTable";
        OleDbDataAdapter da = new OleDbDataAdapter(tmpString, myConnection);
        DataSet mdbDs = new DataSet();
        da.Fill(mdbDs);
        GridView2.DataSource = mdbDs;
        GridView2.DataBind();
        myConnection.Close();
        da.Dispose();
        mdbDs.Clear();
        mdbDs.Dispose();
       // GC.WaitForPendingFinalizers();
       // GC.Collect();
    }

  4  结束语

   利用本文的思路设计的程序在VS.2005中调试成功,在实际项目中也已得到应用,图 2为程序运行效果图,为了将转换前后的数据进行对比,转换的结果采用二个GridView分别显示DBF文件和MDB文件的数据。

  图 2

   根据本文提供的思路完全可以进一步设计出一个BDF与MDB文件的转换器。


« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3