C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: エクセルデータとDataSetをマージする


(過去ログ 28 を表示中)

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■13001 / inTopicNo.1)  エクセルデータとDataSetをマージする
  
□投稿者/ まぐねしうむ (1回)-(2008/01/23(Wed) 13:23:35)

分類:[C#] 

ExcelファイルとDataSetのマージに関して教えてください。

現在、ユーザデータを保持しているMDBファイルからエクセルを書き出しています。
エクセルファイルの役割はDBのバックアップです。

ここまでは、作成できているのですが 
出力したエクセルファイルにユーザを追加して、プログラムに読み込ませた際に
MDBファイルとエクセルファイルでマージを行いたいのですが期待通りの動きをしてくれません。

よろしければ、どこが変か教えて頂けないでしょうか?

             try
             {
                 if (File.Exists(ofd.FileName))
                 {
                    // "Data Source" パラメータを変更してください。
                    string sConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + ofd.FileName + "; Extended Properties=Excel 8.0;";

                    //エクセルからDataSetにデータを読ませる
                    string cmd = "SELECT  * FROM [UserData$]";
                    DataSet ds = getXlsSheetData(sConnectionString, cmd, "UserData");
                    c1Fg_SV1.DataSource = ds.Tables[0];

                    //MDBファイルを読み込む
                    DataSet dsUserData = null;
                    string sqlCommand = "SELECT UserID, Pass, RegistDate FROM UserData;";
                    getUserDbData(sqlCommand, ref dsUserData);

                    //dsUserData.Merge(ds, true, MissingSchemaAction.Error);

                    //マージする
                    dsUserData.Merge(ds, false);
                    c1Fg_SV0.DataSource = dsUserData.Tables[0];

                 }
             }

    //エクセルのデータをDataSetに入れる
     public DataSet getXlsSheetData(string conn, string cmd, string tableName)
     {
         OleDbConnection objConn = null;
         OleDbCommand objCmdSelect = null;
         OleDbDataAdapter objAdapter = null;
         DataSet objDataSet = null;

         try
         {
             objConn = new OleDbConnection(conn);
             objConn.Open();
             objCmdSelect = new OleDbCommand(cmd, objConn);
             objAdapter = new OleDbDataAdapter();
             objAdapter.SelectCommand = objCmdSelect;
             objDataSet = new DataSet();
             objAdapter.Fill(objDataSet, tableName);
         }
         catch (OleDbException OleEx)
         {

         }
         finally
         {
             if (objConn != null) { objConn.Dispose(); }
             if (objCmdSelect != null) { objCmdSelect.Dispose(); }
             if (objAdapter != null) { objAdapter.Dispose(); }
             if (objDataSet != null) { objDataSet.Dispose(); }
         }

            return objDataSet;
        }


引用返信 編集キー/
■13013 / inTopicNo.2)  Re[1]: エクセルデータとDataSetをマージする
□投稿者/ シャノン (267回)-(2008/01/23(Wed) 14:53:16)
No13001 (まぐねしうむ さん) に返信
> ここまでは、作成できているのですが 
> 出力したエクセルファイルにユーザを追加して、プログラムに読み込ませた際に
> MDBファイルとエクセルファイルでマージを行いたいのですが期待通りの動きをしてくれません。

現状はどういう動きをするんですか?

> if (objDataSet != null) { objDataSet.Dispose(); }

これがダメそうな気がしますが。
呼び出し元で使うんだから、ここで破棄しちゃダメです。
引用返信 編集キー/
■13020 / inTopicNo.3)  Re[2]: エクセルデータとDataSetをマージする
□投稿者/ まぐねしうむ (2回)-(2008/01/23(Wed) 15:16:24)
お返事有難うございます。

> 現状はどういう動きをするんですか?
エクセルから読み込んだデータ => Grid上に表示OK
マージ後のデータ       => マージ前のMDBのデータと変わらず。

見た目上は、マージが動いてないように見えます。

>> if (objDataSet != null) { objDataSet.Dispose(); }
>
> これがダメそうな気がしますが。
> 呼び出し元で使うんだから、ここで破棄しちゃダメです。
コメントアウトして確認してみましたが、変化なしです。


引用返信 編集キー/
■13029 / inTopicNo.4)  Re[3]: エクセルデータとDataSetをマージする
□投稿者/ 七曜 (36回)-(2008/01/23(Wed) 16:11:58)
No13020 (まぐねしうむ さん) に返信
getUserDbDataが無いので不明な部分がありますが、
Mergeする側とされる側のテーブル名(だったかな?)あっていますか。
Mergeメソッドは、デフォルトだとMergeする側とされる側で不一致(スキーマなのかテーブル名なのかはうろ覚え・・・)すると
新たにテーブルを作ったりします。(要はDataSet自体のSchemaを書き換える。)

ですので、ステップ実行で
 dsUserData.Merge(ds, false);
この行の実行結果のDataSetのTablesを見てみて下さい。
Merge前とMerge後でTables.Countが増えるようなら、別のテーブルとしてマージされていると思われますので
正しくMergeされる条件を満たす様に修正する必要があります。

引用返信 編集キー/
■13040 / inTopicNo.5)  Re[4]: エクセルデータとDataSetをマージする
□投稿者/ まぐねしうむ (3回)-(2008/01/23(Wed) 20:13:18)
> getUserDbDataが無いので不明な部分がありますが、
下記にCopyさせて頂きます。

>  dsUserData.Merge(ds, false);
> この行の実行結果のDataSetのTablesを見てみて下さい。
ご指摘の通り、Talbesが増えておりました。
そこで、表示するテーブルを変更した所正しくマージされたデータが表示されました。

ただ、このままだとスキーマ?が変更されていると思うので
dsUserData.Tables[0].TableName = "UserData";
 でTable名を変更した所、またマージされなくなってしまいました。
(変更前はMDBから取得したDataSet側のTableNameが「Table」になっていました。

TableName変更後マージしたDataSetのTablesの個数を確認した所
1個なのでなんらかのマージの処理は行っていると思います。

お手数ですが引き続き、お付き合いください。

また、
http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/cpref/html/frlrfSystemDataDataSetClassMergeTopic2.asp
によると、
「Merge メソッドが呼び出されたときは、スキーマが変更されている可能性があるため、
 2 つの DataSet オブジェクトのスキーマが比較されます。」と記載があります。

エクセル側のスキーマとは一体どれになるのでしょうか?

◆以下getUserDbDataのコード

        private bool getUserDbData(string strOlecommand, ref DataSet ds)
        {
            if (!Class.Cls_Sql.getSqlData(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\m\user.mdb;Jet OLEDB:Database Password=????", strOlecommand, ref ds))
            {
                return false;
            }
            return true;
        }

 public static bool getSqlData(string strOleDbConn, string strOlecommand, ref DataSet ds)
        {
            OleDbConnection oleDBcon = null;
            OleDbDataAdapter oleDbAda = null;

            try
            {
                oleDBcon = new OleDbConnection(strOleDbConn.ToString());
                oleDbAda = new OleDbDataAdapter(strOlecommand, strOleDbConn.ToString());
                ds = new DataSet();
                oleDbAda.Fill(ds);
            }
            catch (OleDbException Oex)
            {
                //ExceptionCheck.run(Oex, true);
                return false;
            }
            finally
            {
                //ds.Dispose();
                oleDbAda.Dispose();
                oleDBcon.Dispose();
            }
            return true;
        }

引用返信 編集キー/
■13066 / inTopicNo.6)  Re[5]: エクセルデータとDataSetをマージする
□投稿者/ 七曜 (37回)-(2008/01/24(Thu) 01:19:35)
No13040 (まぐねしうむ さん) に返信
> TableName変更後マージしたDataSetのTablesの個数を確認した所
> 1個なのでなんらかのマージの処理は行っていると思います。

ですからね、
 dsUserData.Merge(ds, false);
とした場合、スキーマが一致しない場合は追加(MissingSchemaAction.Add)になるので、テーブル名を一致させたら、
次はカラム名も一致しないとカラムが追加されてしまうわけですよ。

で、各データをFillした場合のDataSetに設定されているスキーマは
[DataSet.GetXmlSchema メソッド]
http://msdn2.microsoft.com/ja-jp/library/system.data.dataset.getxmlschema(VS.80).aspx
を使うと見れます。

コードだとこんな感じですかね。
        private DataSet GetData(Boolean showSchema, String excelFilePath, String mdbFilePath)
        {
            String datasetName = "UserInfo";
            String tableName = "UserData";
            String connectionString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + excelFilePath + "; Extended Properties=Excel 8.0;";
            //String commandText = "SELECT * FROM [UserData$]";
            String commandText = "SELECT * FROM [UserDataNew$]";  //1行目にColumnNameにあたる行を追加したSheetを読んでみる。
            DataSet dsExcel = ReadData(connectionString, commandText, datasetName, tableName);
            if (showSchema)
            {
                MessageBox.Show(dsExcel.GetXmlSchema(), "Excel側のスキーマ");
            }

            connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + mdbFilePath + ";";
            commandText = "SELECT * FROM UserData";
            DataSet dsMDB = ReadData(connectionString, commandText, datasetName, tableName);
            if (showSchema)
            {
                MessageBox.Show(dsMDB.GetXmlSchema(), "MDB側のスキーマ");
            }

            dsMDB.Merge(dsExcel, false);
            if (showSchema)
            {
                MessageBox.Show(dsMDB.GetXmlSchema(), "マージ後のMDB側のスキーマ");
            }

            return dsMDB;
        }

        private DataSet ReadData(String connectionString, String commandText, String datasetName, String tableName)
        {
            DataSet dsResult = new DataSet(datasetName);
            using (OleDbDataAdapter oAdapter = new OleDbDataAdapter(commandText, connectionString))
            {
                oAdapter.Fill(dsResult, tableName);
            }

            return dsResult;
        }

ちなみにDataAdapterは、コネクションのOpenはしてくれる(たしかCloseもしてくれる)のと、Disposableなので
例の様に書くと、すっきりしたりして。usingはスコープを抜ける際に対象のオブジェクトをDisposeするので
構造化例外処理を書く場合は、usingの外側でtry...catchしておけばfinallyで後始末しなくってもOKです。

で、試した感じで簡単そうなのは、コード例でも書いていますが
 1行目にColumnNameにあたる行を追加したSheetを読んでみる
です。これだとカラム名が一致するのとある程度はデータタイプも一致するのでスキーマが一致します。

あとは・・・Excel読み込み時のcommandText(SELECT構文)でスキーマが一致するような構文を入れるとかかな。
いずれにしてもExcel側は
 String commandText = "SELECT * FROM [UserData$]";
これで読み込むと1行目の内容がカラム名に設定されるので、スキーマを一致させられない場合は
Mergeメソッドを諦める必要があるかもしれません。
(その場合は、Excel側の行と列をループさせて、mdb側に行の追加をするとかになります。たぶん。)

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -