質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.12%

【コード修正】DBへのアクセス回数を減らしたい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,364

unyuho7

score 5

前提・実現したいこと

先週よりC#の勉強をしているプログラミング初心者です。
現在、VB2010にてとあるバッチプログラムを作成しています。
一度プログラム自体は完成したのですが、少しDBへのアクセス回数が多すぎるのでもっと少なく済む様にしたいと考えています。
考えとしては、最初に使うデータを全部持ってしまえば良いのではと考えていて
ループ内の「同一車輌SEQかつ同一計上年月の固定経費情報を取得」と「取得した固定経費情報をリスト化」しているコードをループの外に持って行きたいです。

発生している問題・エラーメッセージ

T_FixedExpenseテーブルのTrailerSEQとM_TralierのTrailerSEQが一緒のものを絞り込むところで悩んでいます。
ループの外だとmtItemが使えないのはわかるのですが・・・。

ソースコード

 class Program
    {
        static void Main(string[] args)
        {
            //ログ出力のテキストファイルを開く
            Encoding sjisEnc = Encoding.GetEncoding("Shift_JIS");
            StreamWriter writer = new StreamWriter(@"FixedExpenceEntry.Log", true, sjisEnc);

            //バッチ起動時のログ出力
            writer.WriteLine("[" + DateTime.Now + "]" + "FixedExpence Entry Start.");

            //基本月額項目の定数を定義
            const
            int dep1 = 13;
            int dep2 = 19;
            int lease1 = 14;
            int lease2 = 20;
            int volIns1 = 10;
            int volIns2 = 13;
            int cargoIns1 = 10;
            int cargoIns2 = 14;
            int radio1 = 9;
            int radio2 = 11;
            int garage1 = 12;
            int garage2 = 18;
            int chaUse1 = 15;
            int chaUse2 = 22;

            //インスタンスの作成
            ttedb_testEntities entity = new ttedb_testEntities();

            //DBから車輌情報を取得
            {
                IQueryable<M_Trailer> trailer =
                    from a in entity.M_Trailer
                    where
                    a.DeleteFlg == null &&
                    a.WorkDiv == 1 &&
                    (
                    a.Depreciation != 0 ||
                    a.Lease != 0 ||
                    a.VoluntaryInsurance != 0 ||
                    a.CargoInsurance != 0 ||
                    a.Radio != 0 ||
                    a.Garage != 0 ||
                    a.ChassisUsage != 0
                    )
                    select a;


                //車両情報をリストに格納
                List<M_Trailer> mtList = trailer.ToList();



                //トランザクション開始

                using (var ts = new TransactionScope())
                {
                    try
                    {
                        //変数を宣言
                        string argsdate;
                        DateTime dtArgs;
                        DateTime dt;

                        //変数dtを実行日で初期化
                        dt = DateTime.Today;

                        //コマンドライン引数が指定されている時
                        if (0 != args.Length)
                        {
                            //コマンドライン引数を取得
                            string[] cmds = Environment.GetCommandLineArgs();
                            argsdate = cmds[1];

                            //取得した引数がDateTime型に変換できる時
                            if (DateTime.TryParse(argsdate, out dtArgs))
                            {
                                //DateTime型に引数を変換
                                DateTime date = DateTime.Parse(argsdate);
                                dt = date;
                            }
                            //取得した引数がDateTime型に変換出来ない時
                            else
                            {
                                //エラーログを出力
                                writer.WriteLine("[" + DateTime.Now + "]" + "Parameter is not available.");
                                throw new System.ArgumentException("Parameter is not available");
                            }
                        }

                        //月初日を定義
                        DateTime dateF = new DateTime(dt.Year, dt.Month, 1);

                        //月末日を定義
                        DateTime dateL = new DateTime(dt.AddMonths(1).Year, dt.AddMonths(1).Month, 1).AddDays(-1.0);

                        //固定経費データ出力開始時ログ出力
                        writer.WriteLine("[" + DateTime.Now + "]" + "Deta Create Start." + "[" + mtList.Count() + "]");

                        //大ループ開始
                        foreach (var mtItem in mtList)
                        {
                            //同一車輌SEQ、計上年月の固定経費情報を取得  
                            IQueryable<T_FixedExpense> sameExpense = from e in entity.T_FixedExpense
                                                                     where e.TrailerSEQ == mtItem.TrailerSEQ &&
                                                                           e.AddUpMonth.Year == DateTime.Today.Year &&
                                                                           e.AddUpMonth.Month == DateTime.Today.Month
                                                                     select e;

                            //取得した固定経費情報をListに格納
                            List<T_FixedExpense> tfeList = sameExpense.ToList();

                            //運転手情報から車両情報に紐付いているDriverSEQを抽出
                            IQueryable<int> driver = from d in entity.M_Driver
                                                     where d.TrailerSEQ == mtItem.TrailerSEQ
                                                     select d.DriverSEQ;

                            //紐付かない場合はnull、紐付いている場合は一件取得する
                            int? driverseq = null;

                            if (driver.Count() > 0)
                            {
                                driverseq = driver.Single();
                            }

                            //変数を定義
                            int expenseSEQ;
                            short rowSub;

                            //データーベースへ登録開始時ログ出力
                            writer.WriteLine("[" + DateTime.Now + "]" + "FDB Entry Start." + "[" + tfeList.Count() + "]");

                            //固定経費データがない場合は新しく登録
                            if (tfeList.Count() == 0)
                            {
                                T_FixedExpense fe = new T_FixedExpense()

                                {
                                    AddUpMonth = dateF,
                                    TrailerSEQ = mtItem.TrailerSEQ,
                                    DriverSEQ = driverseq,
                                    CreateDatetime = DateTime.Now,
                                    CreateUser = 2

                                };
                                entity.AddToT_FixedExpense(fe);
                                entity.SaveChanges();

                                expenseSEQ = fe.FixedExpenseSEQ;

                                rowSub = 1;
                            }
                            else
                            {
                                //抽出した固定経費データを1件取得(FixedExpenceSEQ)
                                expenseSEQ = tfeList.Single().FixedExpenseSEQ;

                                //取得した固定経費から詳細データの連番を取得
                                var row2 = from r in entity.T_FixedExpenseDetails
                                           where r.FixedExpenseSEQ == expenseSEQ
                                           select r.FixedExpenseRow;

                                //件数が0なら1
                                if (row2.Count() == 0)
                                {
                                    rowSub = 1;
                                }

                                //件数が1以上なら連番の最後に+1
                                else
                                {
                                    rowSub = (short)(row2.Max() + 1);
                                }
                            }

補足情報(言語/FW/ツール等のバージョンなど)

ソースコードを全て載せると長すぎるのか投稿出来なかったので端折ってあります。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

cmds[1] が固定なので、コマンドラインパラメタの解析処理をmain先頭にいどうする。

最初のクエリが右、次のクエリが左の内部結合にすれば一発で全部取ってこれませんか。

linq の内部結合

https://msdn.microsoft.com/ja-jp/library/bb397941.aspx

今の実装だと最初のsql の実行結果の取得、次のsqlは、最初のsqlの実行結果に対して逐次問い合わせになるので効率よく無いですね。2つのクエリの接続先が異なるdbである場合は、
http://oshiete.goo.ne.jp/qa/6798209.html#bmb=1
こういうやり方もあるようです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/23 08:48

    ご教授ありがとうございます。
    お答えいただいた方法で無事動作テストまで完了いたしました。
    プログラムの実行速度も早くなり、またひとつ理解が進んだと思います。
    ありがとうございました。

    キャンセル

0

ふと思ったんですが単純に別処理で「車輌SEQ別の年月毎の固定経費情報」を取得して「固定経費情報」のコレクション(Dictionary)として持っておけばよいような気がしますが、ボリューム感がわかりませんのでなんともですが...

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/10/23 08:51

    ご教授ありがとうございます。
    そこまで大規模なデータを処理するわけではないので、いただいた方法でプログラムを作ってみましたがデバッグ時に分かりやすいコードが出来ましてこれもまた良いなと感じました。
    色々な考え方があってプログラミングは奥が深いです・・・。
    ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る