Curl Global Community

Full Version: 修正したレコードだけを抽出したい
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
現在、マスタメンテのような処理を考えており、
マスタ上の全件レコードを取得し、グリッドで直接、修正を行い、登録をしたいと考えています。

登録時は、現在クライアント側に持っているデータをすべて送信し、
テーブルごとデータを入れ替える(デリートインサート)方法もあると思うのですが、
出来れば、「修正したレコード」のみを抽出して登録したいと思っています。

当初、Record.state を参照することで判断しようかなと思っていたのですが、
Record.stateは、対象のレコードに対して、どんな修正が発生しても
状態を変更してしまうという認識なので、
たとえば、削除フラグ用のカラムでチェックボックスをON or OFF しても、
Recotd.state は変更させたくないという場合には対応できないと思っています。

このような場合つまり、「修正とみなしたくない修正」がある場合は、
どのような実装が考えられますか?

アイディアをお持ちのかたがいらっしゃったら教えてください。

最初は、RecordModified を利用すればできるかな、と思っていたのですが、
RecordSet.batch-events? =true 時の修正はRecordModified が発生しないため、
不十分だということに気が付きました。

RecordsBulkChanges のフィールドで、変更が発生したレコードの一覧が取れるとうれしいのですが・・・。

もしアイディアをお持ちの方は教えてください。

Code:
{def fields:RecordFields =
    {RecordFields
        {RecordField "select", domain = bool, caption = "選択"},
        {RecordField "user-id", domain = String, caption = "番号"},
        {RecordField "First", domain = String, caption = "名前"},
        {RecordField "Last", domain = String, caption = "苗字"},
        {RecordField "Age", domain = int, caption = "年齢"},
        {RecordField "updated?", domain = bool, caption = "修正?"}
    }
}

{def rs =
    {RecordSet
        fields,
        {RecordData First = "John", Last = "Smith", Age = 25},
        {RecordData First = "Jane", Last = "Smith", Age = 29},
        {RecordData First = "Jane", Last = "Jones", Age = 28},

        {on e:RecordModified do
            {if-non-null rf =  e.field then
                {if rf.name != "select" then
                    set e.record["updated?"] = true
                }
            }
        }
    }
}

{def grid = {RecordGrid record-source = rs, height= 1in}}
{def modifiedgrid =
    {RecordGrid record-source = rs,
        filter = {RecordFilter.from-state  RecordState.modified}
        , height= 1in
    }
}
{def updated-grid =
    {RecordGrid record-source = rs,
        filter = {RecordFilter
                     {proc {r:Record}:bool
                         {return  r["updated?"] asa bool}
                     }
                 }
        , height= 1in
    }
}

{VBox
    "選択チェックボックスを操作しても、修正状態とは判断しない",
    {Table columns = 2,
        "元のレコード", grid,
        "カスタム修正フラグ[修正?(updated?)]を参照"    , modifiedgrid,
        "Record.stateを参照",updated-grid
    }
}


{CommandButton
    label = "一括変更",
    || RecordModified が発生しないため、カスタム修正フラグの値を変更できない
    {on Action do
        {with rs.batch-events? = true do
            {for r in rs do
                set r["Age"] = 100
            }
        }
    }
}
独自のレコードセットを作成すればなんとかなりそう、なのかな?

正直、あまり RecordSet には手を入れたくないところです。
独自クラスを使わなくて済む方法、または、
今回のように独自のRecordSet を作成して利用する際の注意点などをご存知のかたは教えてください。


Code:
{define-class public CustomRecord {inherits BasicRecord}
  {constructor public {default ...}
    {construct-super {splice ...}}
  }

  {method public {set name:String, val:any}:void
    let pre-state:RecordState = self.state
    {super.set name, val}

    ||特定のフィールド以外への値変更時に、
    ||修正フラグをセットする
    {switch name
    case "select", "updated?"  do
    else
        {super.set "updated?", true}
    }
  }
}


{define-class public CustomRecordSet {inherits LocalRecordSet}

  {constructor public {default ...}
    {construct-super {splice ...}}
  }

  {method public {new-record}:BasicRecord
    def new-r = {CustomRecord  self}
    {return new-r}
  }

  {method public {commit}:void
    ||コミット時に修正フラグをリセット
    {with self.batch-events? = true do
        {for r in self do
            set r["updated?"] = false
        }
    }
    {super.commit}
  }

}
上記CustomRecordSet の実装ですが、new-recordをオーバーライドするより
allocate-recordをオーバーライドするほうがいいかもしれませんね。
詳細まではわかりませんが、ヘルプにはそうするように記述がありますので。
Yuhki さん、ありがとうございます。
BasicReocrdSet のヘルプをよく見ていませんでした。すいません。

new-record のオーバーライドでは、レコードセットに対して RecordData を追加しても
カスタマイズしたレコードを返してくれないので、どうすればよいか悩んでいたのですが、
allocate-record をオーバーライドするようにすれば解決しました。

new-record の内部で、allocate-record を呼んでいるから、という認識です。

「TRUEの値をFALSEに修正したけど、またTRUEに修正した」場合に、
元に戻っているのだから、「変更されたレコード」としては扱いたくない、
というケースでは、スナップショットを取っておいて、比較するほうが簡単な気がしてきました。

Libライブラリの、RecordSetUtil.clone を使って、レコードセットのクローンを作成しています。
(厳密には、レコードフィールドの増減なども判別する必要がありそうですが・・・)


Code:
{import * from COM.CURL.LIB.DATA-ACCESS}
{let snapshot-rs:#RecordSet = null}

{def RECORD-INDEX = "RECORD-INDEX"}

{def rs =
    {RecordSet
        {RecordFields
            {RecordField "select", domain = bool, caption = "選択"},
            {RecordField RECORD-INDEX, domain = int, caption = "番号"},
            {RecordField "First", domain = String, caption = "名前"},
            {RecordField "Last", domain = String, caption = "苗字"},
            {RecordField "Age", domain = int, caption = "年齢"},
            {RecordField "updated?", domain = bool, caption = "修正?"}
        }
    }
}

{def grid = {RecordGrid record-source = rs, height= 2in}}

{do
    {with rs.batch-events? = true do
        {for i:int = 0 to 3 do
            def new-r = {rs.new-record}
            set new-r[RECORD-INDEX] = i
            {rs.append new-r}
        }
        {rs.commit}
    }
}

{value grid}

{CommandButton
    label = "スナップショット",
    {on Action do
        {if-non-null rs = grid.record-source then
            set snapshot-rs = {RecordSetUtil.clone rs}
        }
    }
}


{CommandButton
    label = "比較",
    {on Action do
        {if-non-null snapshot-rs then
            {if-non-null rs = grid.record-source then
                def vb = {VBox}
                {for r key idx:int in grid.records do
                    {if-non-null cmp-r =
                        {snapshot-rs.select-one
                            filter = {RecordFilter
                                         {proc {tg-r:Record}:bool
                                             {if r[RECORD-INDEX] == tg-r[RECORD-INDEX] then
                                                 {return true}
                                              else
                                                 {return false}
                                             }
                                         }
                                     }
                        }
                     then
                        let equal?:bool = true
                        {for rf in rs.fields do
                            {if r[rf.name]  != cmp-r[rf.name] then
                                set equal? = false
                                {break}
                            }
                        }

                        {if not equal? then
                            {vb.add idx + 1 & "行目" & r["First"]}
                        }

                    }
                }
                {if vb.child-array.size > 0 then
                    {vb.add index = 0 , "以下のレコードは修正されています"}
                    {popup-message vb}
                 else
                    {popup-message "編集中のレコードはありません"}
                }
            }
        }
    }
}
あまり知られてませんが、RecordSet内のRecordは
commit時の値(revert時に戻す値)を内部的に保持しており、
getメソッドの引数 pending? をfalseにすることでその値を
取得することができます。

{record.get "hoge", pending? = false}
または
record["hoge", pending? = false]

編集中のレコードを値の比較によって抽出する場合、別の目的でcommitを使用していなければ
これを使ったほうがよさそうな気がします。


おお、pending? で Record.state=ReocrdState.original だったときの値を保持してくれているのですね!
知りませんでした。

たしかにヘルプにも、そのように記載されていますね。


TextField で、ValueFinished 時に、前の値と比較したい場合が良くあるので、
同じような機能があればうれしいのになぁ。