|
|
本帖最后由 Test 于 2011-10-5 13:16 编辑
Introduction The class needs a table on a SQL Server somewhere to import into, a connection to that database, a file to load, the names of the fields to load the data into and the possessions in the file to load. I set this up so that everything can come from application settings, and put a quick WPF file browser front end together to demonstrate how to use the class.
Background Everywhere I have worked, it has been important to be able to load fixed width files from mainframe reports that come from data sources that can't or at-least aren't provided by web services, ODBC or other sources. Every time there is a new version of Visual Studio, this gets a little easier to write. This is my latest class to do the import.
Using the Code The simplest way to use my BulkLoad class is to make setting strings for what needs to be loaded and pass them to the BulkLoadFromStrings function. In this example I have set up everything as app settings.
This is what the config file looks like:
- <configuration>
- <configsections>
- <sectiongroup name=""userSettings"" publickeytoken="b77a5c561934e089""
- culture="neutral," version="2.0.0.0,"
- type=""System.Configuration.UserSettingsGroup,">
- <section name=""Bulk_Import.Properties.Settings""
- publickeytoken="b77a5c561934e089"" culture="neutral," version="2.0.0.0,"
- type=""System.Configuration.ClientSettingsSection,"
- requirepermission=""false"" allowexedefinition=""MachineToLocalUser"">
- </sectiongroup>
- </configsections>
- <usersettings>
- <bulk_import.properties.settings>
- <setting name=""TableName"" serializeas=""String"">
- <value>drcAlden</value>
- </setting>
- <setting name=""FieldNamesCSV"" serializeas=""String"">
- <value>CLSNumber,YrPeriod,Vendor,Department,BoxCode,StoreNumber,StoreName,
- TypeScan,UPC , Manufac,Description,Qty ,Base ,Credit ,GSNumber</value>
- </setting>
- <setting name=""DefaultDir"" serializeas=""String"">
- <value>C:\</value>
- </setting>
- <setting name=""DefaultFile"" serializeas=""String"">
- <value>FixedWidthFile.txt</value>
- </setting>
- <setting name=""FormatCSV"" serializeas=""String"">
- <value>4-8 ,10-14 ,15-22 ,23-26 ,27-36 ,38-48 ,48-77 ,
- 78-80 ,80-94 ,94-103 ,103-123 ,124-133 ,133-146 ,147-160,161-170</value>
- </setting>
- </bulk_import.properties.settings>
- </usersettings>
- <connectionstrings>
- <add name=""DamageReclaimEntities"" security="True;MultipleActiveResultSets=False"""
- catalog="Database;Integrated" source="Server;Initial"
- string=""Data" providername=""System.Data.EntityClient""
- connectionstring=
- ""metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/
- Model1.msl;provider=System.Data.SqlClient;provider">
- <add name=""Bulk_Import.Properties.Settings.DamageReclaimConnectionString""
- security="True"" catalog="Database;Integrated"
- source="DBServer;Initial" providername=""System.Data.SqlClient""
- connectionstring=""Data">
- </connectionstrings>
- </configuration>
复制代码
The app settings were just added by right clicking on the project file though, so, don't worry about having to retype a bunch of perfectly valid XML unless you are into all that.
This BulkLoadFromStrings function basically calls the class's parse routines on these strings and uses them to Load the file.
- /// <summary>
- /// Does bulk load based on settings for file and table to be loaded.
- /// </summary>
- /// <param name=""TableName"">Name of table to be loaded.</param>
- /// <param name=""FieldNamesCSV"">Comma Separated list of field names </param>
- /// <param name=""FieldPositionCSV"">Comma separated list of field positions
- /// separated by dashes</param>
- /// <param name=""FileNameAndPath"">Path to fixed width file with data to be
- /// loaded.</param>
- /// <param name=""SQLConnectionString"">Connection string for DB to load
- /// data in.</param>
- /// <returns></returns>
- public int BulkLoadFromStrings ( string TableName_in
- , string FieldNamesCSV_in
- , string FieldPositionCSV_in
- , string FileNameAndPath_in
- , string SQLConnectionString_in
- )
- {
- int iRecordsLoadedOut = 0;
- BulkLoadFields blfldsToLoad;
- BulkLoadTable bltblToLoad;
- SqlConnection con = null;
- Stream strmToLoad = null;
- DataTable dtToLoad = null;
- int iRecordsPreLoaded = 0;
- con = MakeConnection(SQLConnectionString_in);
- blfldsToLoad = new BulkLoadFields(FieldNamesCSV_in, FieldPositionCSV_in);
- bltblToLoad = MakeBulkLoadTable(TableName_in, con, blfldsToLoad.FieldNames);
- strmToLoad = FileToStream(FileNameAndPath_in);
- dtToLoad = bltblToLoad.Table;
- iRecordsPreLoaded = LoadTable(ref dtToLoad, blfldsToLoad.FieldPositions,
- strmToLoad);
- strmToLoad.Close();
- strmToLoad = null;
- bltblToLoad.Table = dtToLoad;
- iRecordsLoadedOut = DoBulkLoad(bltblToLoad, con);
- AddExportDate(FileNameAndPath_in, con.Database.ToString(),
- con.DataSource.ToString());
- return iRecordsLoadedOut;
- }
复制代码
There are 2 structures that the class uses to pass things around. The BulkLoadFields structure is where the collection of field positions and names are stored, and the BulkLoadTable is simply a datatable with these SQLBulkInsert maps set up for each of its columns. These maps turned out to be extremely important to getting the Bulk insert to work.
Because the SQLBulkCopy object seemed to be so sensitive to datatype and data size differences, the best solution seemed to be to create a table to load based on an existing table. I saw other examples wherein data readers did something similar, and it seems like there should be a better way (or at least one less specific to SQL Server) to get a table definition, but selecting the description from SQL's system tables has worked well for me.
By Alden John Snow
http://www.codeproject.com/KB/WPF/SQLBulkLoad_Fixed_Wdh_TXT.aspx
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?注册
×
|