windows8データの保存について(HTML+JS)
Windowsストアアプリ(旧メトロアプリ)の開発に関してちょっとまとめときます。
Windowsストアアプリでデータの保存をするとき、デフォルトで用意されてるのはKVSのような連想配列です。
valueは文字列のみ保存可能なものです。
つまり、永続的に保存させたい時は
test["key"] = "value"
こんな感じで保存します。
http://msdn.microsoft.com/ja-jp/library/windows/apps/hh465118.aspx
当初JSからanyPC向けにRDBMSを使えないと思ってたためにこの方法に頼るしかなかったためにこの方法で実装しました。(今ではsqliteが使えるようです。)
でも、containerとかそういうのを意識してずっとグチャグチャ書くのもあれだし、いつかRDBMSに変更するかもしれないしってことで
データの保存はラッパーを通すことにしました。
あと、連想配列って考えると、最新レコード4件とかそういうのを考慮するのがめんどくさいってのもここで解決させます。
外側からはORマッパー触る感覚で操作できればいいかな!そんなに複雑なことをやるつもりもないので、実装は最低限にしておきます。
valueには文字列以外にcompositeとよばれるObjectが代入できる、
compositeは普通のオブジェクトと同じように値を持つことができる。
しかしcompositeのvalueも文字列しか代入できないので注意
containerは連想配列に代入する連想配列のようなもの。
でもcontainerは普通に代入するんじゃないので注意
つまり、こんな感じ(以下イメージの話で完全なソースではありません)
- Containerを使っていないとき普通に保存する
1: var localSetting = WinJS.Application.local;
2: localSetting['key'] = 'value'; //Keyに対して単なる文字列かAtomicオブジェクトしか代入できない
- compositeオブジェクトを使って代入
1: var localSetting = WinJS.Application.local;
2: var atomic = new Windows.Storage.ApplicationDataComposite();
3: atomic["key1"] = "value1";
4: atomic["key2"] = "value2";
5: localSetting['key'] = atomic; //compositeならオブジェクトのように保存できる
- Containerを使うとこんなことができる
1: var localSetting = WiJS.Application.local;
2: var container = localSetting.createContainer('ContainerName',
Windows.Storage.ApplicationDataCreateDisspositon.Always);
3: var localSetting.containers.lookup('ContainerName').values['key'] = 'value';
最初は
KVSでしかも文字列のみとかWindowsストアアプリでデータ保存系のアプリは難しくね?
って思ってたんだけど・・・
これらを使うと意外にちゃんとデータ管理できる!
って感じでここまでが準備段階。
目標はなんちゃってRDBなのでほんとデータ保存して引っ張れたらOK
データ構造(そんなすごい物ではないが)から
これを
テーブル名 | |
レコード | |
レコード | |
レコード | |
レコード |
こんな感じで実装
container名 | |
compositeObj | |
compositeObj | |
compositeObj | |
compositeObj |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
でcompositeObjは必ずユーニークなキーとなるindexを持っている。
indexは0から始まり、compositeObjのindexもオートインクリメントされて保存される。
それで
container[indexの値] = compositeObj;
こんな感じで実際に保存されている。
[例]
container[0] = compositeObj;
container[1] = compositeObj;
container[2] = compositeObj;
で次に保存されるcompositeObjに割り当てられるindex値をcontainerが直接持っている。この場合は
container['index'] = 3
こんな感じ。
まとめるとcontainerの中身は
container['index'] = 6;
container[0] = compositeObj;
container[1] = compositeObj;
container[2] = compositeObj;
container[3] = compositeObj;
container[4] = compositeObj;
container[5] = compositeObj;
こんな感じで保存すると決めると結構ちゃんと保存できる。
(あっ、これだと不整合起きるんじゃねとかはとりあえずなしで)
javascriptってシングルスレッドだし、アプリのデータに双方が同時にアクセスすることは多分ないから大丈夫なはず・・・・
こんな構造って決めとくと、割とあとはスムーズ。
例えばテーブル作るのこんな感じ
/** * @param tableName * String 作成するテーブル名 * @return resultStatus * Boolean テーブル作成がうまくいったかどうか * *考えられるエラー原因: テーブルがすでに存在する **/ function createTable(tableName){ var resultStatus = false; if (localSettings.containers.hasKey(tableName)) { return resultStatus; } else { var container = localSettings.createContainer(tableName, Windows.Storage.ApplicationDataCreateDisposition.Always); localSettings.containers.lookup(tableName).values["index"] = 0; resultStatus = true; return resultStatus; } }
レコードの追加とか。
/** * 指定したテーブルにレコードを追加 * @param recordObj,tableName * recordObj Object 追加したいレコードオブジェクト(生のオブジェクト) * tableName String レコードを追加したいテーブル名 * * @return resultStatus * 成功したらIndex * 失敗したらfalse * *考えられるエラー原因: テーブルが存在しない **/ function insertRecordToTable(recordObj,tableName){ var resultStatus = false; if(localSettings.containers.hasKey(tableName)){ var index = parseInt(localSettings.containers.lookup(tableName).values["index"]); recordObj.index = index; localSettings.containers.lookup(tableName).values[index] = toAtomic(recordObj); localSettings.containers.lookup(tableName).values["index"] = index+1; resultStatus = recordObj.index; return resultStatus; } else{ return resultStatus; } }
全てのソースはあとでGithubに上げます。
まぁ大したもんじゃないんですけど。。。。
最後に
この方法が実用的であるかどうかって話はあると思うんですが、
データ保存を実際のアプリロジックに含めず上記のように分離してインターフェースからアクセスすることで
データ保存の処理を丸々入れ替えても現在のインターフェースを実装すればアプリはそのまま動くので、こういう作り方は有効だなと!(当たり前っちゃ当たり前なんだが。。。。)
daoのデザインパターンに近いんですかね???
まぁもっとSqliteの情報とか出てきたら入れ替えてみようかと思います。そもそもJSからいじれるのかとか、アーキテクチャ依存しないのかとか
GitHubに上げました
https://github.com/ukinau/VDB_windows8/blob/master/vmDb.js
すこし、インデントとかずれてるけど気にしない気にしない
久しぶりの更新でした。