W tym artykule przedstawione zostanie jak można przenieść informacje z DataSet'a (układ i zawartość) do bazy danych opartej o Microsoft SQL Server (również w wersji Express). W tym celu zostaną wykorzystane SQLServer Management Objects (SMO) i SqlBulkCopy.
Ze wspomnianym problem spotkałem się już jakiś czas temu (przeczytajcie na devPytaniach: „Jak z DataSet’a wytworzyć bazę danych?”), ale dopiero teraz znalazłem chwilę czasu, aby rozwiązanie opisać.
Podstawy wykorzystania SQLServer Management Objects (SMO)
Referencje do bibliotek
Przed
przystąpieniem do wykorzystania SMO w naszej aplikacji należy dodać
do projektu odpowiednie referencje (poniżej przedstawiono
lokalizacje domyślne):
- %programfiles%\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.ConnectionInfo.dll
- %programfiles%\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.Management.Sdk.Sfc.dll
- %programfiles%\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.Smo.dll
- %programfiles%\Microsoft SQL Server\100\SDK\Assemblies\Microsoft.SqlServer.SqlEnum.dll
Później
wskazujemy, z jakich dodatkowych przestrzeni adresowych będziemy
korzystać:
- using Microsoft.SqlServer;
- using Microsoft.SqlServer.Server;
- using Microsoft.SqlServer.Management.Smo;
- using Microsoft.SqlServer.Management.Common;
Obiekt serwera
Aby podłączyć
się do serwera SQL należy:
SqlConnection Connection = new SqlConnection( ConnectionString ); //SMO Server object setup with SQLConnection. Server MySQLServer = new Server( new ServerConnection( Connection ) );
Obiekt bazy danych
Aby utworzyć bazę
danych należy:
Database MyDataBase = new Database( MySQLServer, DataBaseName ); MyDataBase.Create();
Obiekt tabeli
Aby utworzyć
tabelę w bazie danych należy:
Table myTable = new Table( MyDataBase, DataSetTable.TableName ); // ... // Creation of Columns, Keys, etc... //Create the Destination Table myTable.Create();
Obiekt kolumny
W celu utworzenia kolumny należy:
myColumn = new Column( myTable, dc.ColumnName ); myColumn.DataType = GetDataType( dc.DataType.ToString(),dc.MaxLength ); //GetDataType - created SQL Server DataType based on originall type and max length if ( dc.AutoIncrement ) { myColumn.Identity = true; myColumn.IdentityIncrement = dc.AutoIncrementStep; myColumn.IdentitySeed = dc.AutoIncrementSeed; } myTable.Columns.Add( myColumn );
Obiekt indeksu (klucze dla tabeli)
Aby ustawić dla tabeli klucz główny
należy:
Index index = new Index( myTable, "PrimaryID" + myTable.Name ); index.IndexKeyType = IndexKeyType.DriPrimaryKey; foreach ( DataColumn pk in DataSetTable.PrimaryKey ) { index.IndexedColumns.Add( new IndexedColumn( index, pk.ColumnName ) ); } myTable.Indexes.Add( index );
Podstawy SqlBulkCopy
SqlBulkCopy pozwala na efektywne
ładowanie danych do bazy danych z pliku XML lub DataSet'a.
Najpierw należy dodać referencję do
Assembly System.Data.dll. Późniejsze wykorzystanie jest już bardzo
proste:
// Bulk Copy loader System.Data.SqlClient.SqlBulkCopy bulkCopy = new System.Data.SqlClient.SqlBulkCopy( MyConnectionString ); //Destination table: bulkCopy.DestinationTableName = String.Format( "\"{0}\"", dataSetTable.TableName ); try { //writing to server bulkCopy.WriteToServer( dataSetTable ); } catch ( Exception ex ) { MessageBox.Show( dataSetTable.TableName + ":" + ex.Message ); } finally { //closing bulk copy connection bulkCopy.Close(); }
Gotowy kod rozwiązujący tytułowy problem (DataSet -> MsSQL)
Na sam koniec
zapraszam do zapoznania się z gotowym kodem rozwiązujący tytułowy
problem, czyli przeniesienie informacji z DataSet'a (układ i
zawartość tabel) do bazy danych:
class DataSet2SMO { public static void CreateDataBase( string ConnectionString, string DataBaseName, DataSet SourceDataSet, bool LoadData ) { SqlConnection Connection = new SqlConnection( ConnectionString ); //SMO Server object setup with SQLConnection. Server MySQLServer = new Server( new ServerConnection( Connection ) ); //Create a new SMO Database giving server object and database name Database MyDataBase = new Database( MySQLServer, DataBaseName ); MyDataBase.Create(); foreach ( DataTable dt in SourceDataSet.Tables ) { CreateDataTable( MySQLServer.Databases[ DataBaseName ], dt ); if ( LoadData ) { //loading Data (if required) string NewConnectionString = String.Format( "{0};Initial Catalog={1};", ConnectionString, DataBaseName ); // Bulk Copy loader System.Data.SqlClient.SqlBulkCopy bulkCopy = new System.Data.SqlClient.SqlBulkCopy( NewConnectionString ); //Destination table: bulkCopy.DestinationTableName = String.Format( "\"{0}\"", dt.TableName ); try { //writing to server bulkCopy.WriteToServer( dt ); } catch ( Exception ex ) { MessageBox.Show( dt.TableName + ":" + ex.Message ); } finally { //closing bulk copy connection bulkCopy.Close(); } } } } private static void CreateDataTable( Database MyDataBase, DataTable DataSetTable ) { Table myTable = new Table( MyDataBase, DataSetTable.TableName ); //SMO Column object referring to destination table. Column myColumn; //Add the column names and types from the datatable into the new table //Using the columns name and type property foreach ( DataColumn dc in DataSetTable.Columns ) { //Create columns from datatable column schema myColumn = new Column( myTable, dc.ColumnName ); myColumn.DataType = GetDataType( dc.DataType.ToString(), dc.MaxLength ); //GetDataType - created SQL Server DataType based on originall type and max length if ( dc.AutoIncrement ) { myColumn.Identity = true; myColumn.IdentityIncrement = dc.AutoIncrementStep; myColumn.IdentitySeed = dc.AutoIncrementSeed; } myTable.Columns.Add( myColumn ); } //Create a primary key index Index index = new Index( myTable, "PrimaryID" + myTable.Name ); index.IndexKeyType = IndexKeyType.DriPrimaryKey; foreach ( DataColumn pk in DataSetTable.PrimaryKey ) { index.IndexedColumns.Add( new IndexedColumn( index, pk.ColumnName ) ); } myTable.Indexes.Add( index ); //Create the Destination Table myTable.Create(); } private static DataType GetDataType( string dataType, int MaxLength ) { DataType DTTemp = null; switch ( dataType ) { case "System.Decimal": DTTemp = DataType.Decimal( 2, 18 ); break; case ( "System.String" ): DTTemp = DataType.VarChar( MaxLength ); break; case "System.Int16": case "System.Int32": case "System.UInt16": case "System.UInt32": DTTemp = DataType.Int; break; case "System.Double": case "System.Single": DTTemp = DataType.Real; break; case "System.Int64": DTTemp = DataType.BigInt; break; case "System.DateTime": DTTemp = DataType.DateTime; break; } return DTTemp; } }
I przykład wykorzystania:
MySchema myDataSet = new MySchema(); myDataSet.ReadXml( xmlfilename ); string connectionstring = @"Data Source=localhost\SQLEXPRESS;Integrated Security=True"; DataSet2SMO.CreateDataBase( connectionstring, "MyNewDatabase", myDataSet, true );
Źródła i dalsze informacje na ten temat
Zapraszam również
do zapoznania się ze źródłami, na podstawie których powstało
niniejsze opracowanie:
Czy to już wszystko?
Na pewno to
dopiero podstawowe informacje o SMO i SqlBulkCopy. Nie jest to też
przedstawienie pełnego rozwiązania. Rozwinąć można również
temat mapowania typów danych. Nie uwzględniłem powiązań między
tabelami i kluczy obcych. Przyznam, że nie potrzebowałem akurat
takiej funkcjonalności, ale może ktoś inny zaproponuje co tu można
jeszcze zrobić. W każdym razie wydaje mi się, że zaprezentowane
rozwiązanie wystarczy w wielu przypadkach.
Brak komentarzy:
Prześlij komentarz