@IT会議室は、ITエンジニアに特化した質問・回答コミュニティ「QA@IT」に生まれ変わりました。ぜひご利用ください。
- PR -

ADO.NET-OLE接続によるExcel出力について

投稿者投稿内容
ひんしつ
会議室デビュー日: 2008/04/03
投稿数: 9
投稿日時: 2008-04-03 21:31
ASP.NETにて、ADO.NET-OLE接続によるExcel出力を行っています。(VS2005)

少ないデータの場合は問題なく完了するのですが
多いデータになると以下の問題が発生します。

実際にはExcelに出力されていないのに処理が完了し
その直後のファイル読み取り処理で
「別のプロセスで使用されているため、プロセスはファイル 'C:\test.xls' にアクセスできません。 」エラーの発生。

上記は、まだExcel書き込み中のため、ファイルアクセス時にファイルを
開けず、エラーになるようです。
調べてみると仕様で、OLEによる書き込みは非同期で書き込むそうですが
これを回避する方法はありますでしょうか。

参考までにソースは以下になります。

protected void Button1_Click(object sender, EventArgs e)
{

DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.OleDb");
using (DbConnection con = factory.CreateConnection())
{
con.ConnectionString = String.Format("Provider=Microsoft.Jet.OLEDB.4.0; Data Source={0}; Extended Properties=\"Excel 8.0;HDR=YES;\" ", @"C:\test.xls");
con.Open();

using (DbTransaction tran = con.BeginTransaction())
{
for (int i = 0; i < 500; i++)
{
DbCommand cmd = con.CreateCommand();
cmd.Transaction = tran;
cmd.CommandText = "update [Sheet1$A1:D1000] set A=? where row = " + (i + 1);

DbParameter para = cmd.CreateParameter();
para.Value = "a";
cmd.Parameters.Add(para);

cmd.ExecuteNonQuery();
}

tran.Commit();
}

if (con != null)
{
con.Close();
}

}

Response.ContentType = "application/octet-stream";
Response.AppendHeader("Content-Disposition", "inline; filename=" + @"C:\test.xls"); // attachment/inline
Response.WriteFile(@"C:\test.xls");
Response.End();
}

通常、こんな回避をする。あるいはそれは仕様だからどうしようもない
など、ご意見頂けたらと思います。


[ メッセージ編集済み 編集者: ひんしつ 編集日時 2008-04-03 21:32 ]
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2008-04-03 22:20
ASP.NET ですよね?で、ユーザ アクションの、ボタン クリック イベント内で、やっているんですよね?

もう一つボタンを置いて、そのクリック イベントで、Sleep(6 * 1000) (6分)とかやってみてください。3分ほどで返ってきますから。


 あなたが作っているのは、ASP.NET、ウェブ アプリケーションだということを、常に意識してください。これは、デスクトップ アプリケーションとは違います。同じような作り方ができますが、違うものです。デスクトップ アプリケーションとは、違う作法があります。
 今回、あなたはその「違う作法」に引っかかったわけです。ウェブにリクエストを出して、長い間ページが更新されない。さて、どうしますか?


 解決方法の一つは、こんな感じ→ASP.NET 1.1 長い処理中に「お待ちください」画面を表示する<wankuma.com>
 リクエストには、、、忘れた。何秒か以内にレスポンスを返してあげてください。


 それから、ドライブのルートにものを書いて、それをダウンロードさせるのは止めましょう。これは、デスクトップ アプリケーションでも同じ。それに、複数のリクエストが同時にあった場合のことも考えましょう。
ひんしつ
会議室デビュー日: 2008/04/03
投稿数: 9
投稿日時: 2008-04-03 23:49
ご返信ありがとうございます。

実は、ASP.NETですけど
実際は、Webサービスで実行し、クライアントはWindowsフォームです。

クライアント側から、このWebサービスは非同期実行で実行されます。
なので、ご心配頂いたところは大丈夫かと思います。

掲示したソースは、テストコードのため、ドライブのルートに
とりあえず置いています。実際は、正しい場所に置かれます。
説明がいろいろと足りなくてすいません。

問題は、OLEでのExcel出力にあります。

しかしなぜ、わざわざASP.NETでサンプルを書いたかというと
コンソールアプリとは異なる動作をしたためです。

コンソールアプリだと、30秒で終わる処理が、ASP.NETだと現状5分かかってしまいました

おそらくAsp.netのプロセスが残っているため、OLEによる出力が遅延しているのでは?と推測しています。

[ メッセージ編集済み 編集者: ひんしつ 編集日時 2008-04-04 08:39 ]
ひんしつ
会議室デビュー日: 2008/04/03
投稿数: 9
投稿日時: 2008-04-07 01:31
いまだ、前進していませんが、これまでにわかったことを
追記します。

http://www.canalian.com/workshop/access/JetCache.html
ちょっと古いですが、↑によると

>書込み時には、implicit transactionでは遅延(非同期)書込み、
>explicit transactionでは、遅延を生じない同期書込みが行われるようになっ
>ています。これも、レジストリで設定されており、前者は ImplicitCommitSync = no、
>後者はUserCommitSync = yesという設定です。

>マルチユーザー環境などで、書き込み遅延が発生しては困るときには、
>同期書き込みを利用します。同期書き込みを行なうには、BeginTrans 〜 CommitTrans
>という、明示的なトランザクションを利用します。
とあります。

もともと、非同期書き込みをサポートしていて、同期書き込みする場合は
明示的なトランザクションを使用すること。らしいですが

BeginTransaction、Commitを行っても非同期で実行されているようです。
ひんしつ
会議室デビュー日: 2008/04/03
投稿数: 9
投稿日時: 2008-04-09 21:58
少し変なことがわかったのでご報告します。

まったく同じコードの
OLEによるExcel出力をNUnitから行うと成功しますが
コンソールアプリから実行するとだめです。

コンソールアプリから実行するとすべて出力されていないExcelファイルが
出力されます。
途中までは書かれているのですが、途中で終わってしまったようなExcelが出力されます。

このNunitから実行した場合と、コンソールでは何か違うのでしょうか。

実行後の後処理?待ちうけ?それともスレッドの作り方?

なにかご存知でしたら、ご助言ください。
ひんしつ
会議室デビュー日: 2008/04/03
投稿数: 9
投稿日時: 2008-04-11 15:39
すっかり独り言状態ですが、

NUnitから実行すれば成功するのは気のせいだったようです。

ただ、コンソールプログラムに変更してSTAThread属性を指定することで
成功する確立があがりました。(OLEを使用する場合は必須?)

しかし、まだ20〜30回に1度は、途中までしか書かれていない
Excelが出力されます。

あと、もうひとつ、実験を行いました。
上記コンソールプログラムの最後に、Excelに出力した値を
OLEで読み込む処理をいれて、書き込まれているかの確認を行いました。

すると、チェック結果は書かれていたが、実際に出力されたExcelには
かかれてないという現象が発生。

これでは、やっぱりいつ書き込みが終了したのかわからないという状況のようです。
ひんしつ
会議室デビュー日: 2008/04/03
投稿数: 9
投稿日時: 2009-03-05 16:31
この件について情報をお持ちの方、いらっしゃいますでしょうか?

書込み処理は正常終了するが、データが書き込まれていないことがまれに発生し
困っています。
デューン
大ベテラン
会議室デビュー日: 2004/04/21
投稿数: 174
お住まい・勤務地: Tokyo
投稿日時: 2009-03-05 20:45
引用:

ひんしつさんの書き込み (2009-03-05 16:31) より:
この件について情報をお持ちの方、いらっしゃいますでしょうか?

書込み処理は正常終了するが、データが書き込まれていないことがまれに発生し
困っています。



OLEでExcelに書き込むという選択をしないので、
気になったことを何点かだけ。


その前に、ちょっと整理させてもらいますが、

現状としては、コンソールアプリケーションに変更したが、
途中までしか出力されない事がある。

でいいですか?


STAThreadはCOMのためにあった方がいいでしょうね。


途中までかかれない現象の場合にパターンは見いだせませんか?
出力量が多いとか。

ログの出力を試みたことは?
(例外が起きていた場合は気づける作りですか?)

元々はWebサービスに組み込んでいたようですが、そこからプロセス作って
実行させているのであれば、どのユーザで実行されせているかとか。


あと気になる点では、
Commandにもusing句を使ってみる
CommandがDisposeされる前にpara.clearを呼んでみる
ぐらいでしょうか


あまり参考にはならないかもしれませんが。

スキルアップ/キャリアアップ(JOB@IT)