Unityで使えるORマッパー作った話


今回は、拙作のライブラリ、Nattoの話をさせていだきます。
https://github.com/adarapata/Natto
![image](https://camo.githubusercontent.com/0b5e557a0114d5d27f3e86d4a41c16ddbc89d72b/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313733343030322f323133383631372f65353365393830342d393333352d313165332d383135342d3231333932366237363639302e6a7067)

## これは何？
Unity上でDBを操作するライブラリです。
MySQL5.6.14 SQLite3.8.74 で動作確認しています。


## 発端
自分のゲームにアイテム情報などを入れるときに、はじめはcsvやtxtファイルを取り込んで使っていたが、不満があった。

- データ打ち込むときに、面倒(txtだったら自分でカンマ区切りしたり、入力順番を意識したり)
- csvはセルを作りたくない、excel入れてない(Googleドライブ使えばいいけど)

なので、別の手段を考えてた時に、DB用意したらいいんじゃないのと思った。

### DBで管理しようと思った理由
- その時にたまたまDBをよく触ってた
- 自分でフォーマット作らなくていい
- クライアントアプリが豊富

こっちがいろいろルール決めたり用意しなくても揃ってるので便利だなと思った。
だけど、アセットストアでそういうのないか探したら、だいたい有料だったので手が出せなかった。
https://www.assetstore.unity3d.com/jp/#!/content/3845

なので、勉強も兼ねて作ってみた。
そのときにRuby on Rails を触っていて、ActiveRecordの機能が便利だったので
それっぽいものに仕上がりました。

## 使い方

使い方はREADMEにだいたい載ってるので、補足説明だけやります。

0 . `ProjectSetting->Player` から `Api Compatibility Level` を `.NET 2.0` にしてください。
![](http://i.gyazo.com/e364b91381aaf6512c15b5143889451d.png)

1. Unityプロジェクト内の任意の場所にclone `git@github.com:adarapata/Natto.git`
 - gitの使い方よくわからないという場合は、画面右下の `Download ZIP` からZIPを落として解凍してください。
![](http://i.gyazo.com/663196ef032f788f3ca75007f74ac863.png)

2. `Assets/StreamingAssets/` 下にdbファイルを配置する(SQLiteの場合)
 - Unityはアプリケーション外にファイルを用意する場合、`StreamingAssets` という名前でディレクトリを作ると、ビルド時にそのまま吐き出してくれます。
  [ref ストリーミングアセット](http://docs-jp.unity3d.com/Documentation/Manual/StreamingAssets.html)


3. `Natto/Resources/DatabaseConfig` に接続情報を設定する
上記ファイルは、MySQLもしくはSqliteに接続する際に必要な情報を保持するオブジェクトです。
`Database Type` のプルダウンを切り替えると、DBの種類に応じて設定できる情報が切り替わります

 SQLiteの場合
 ![](http://i.gyazo.com/1d10df58947664065c8f7d91c545eab8.png)
 `filename:` sqliteのファイル名。 `StreamingAssets/` 下のファイルが読み込まれる。

 MySQLの場合
 ![](http://i.gyazo.com/4cff93dbde9dea69a2248f862be2902c.png)
 `hostname:` ホスト名 `db-hoge.com` or `111.111.1.1` など
 `username:` 接続するユーザ名
 `database:` データベース名
 `port:` ポート番号
 `password:` パスワード 

4. 対応したDaoクラスを作成する。[サンプル](https://github.com/adarapata/Natto/blob/master/Sample/SampleDao.cs)

```csharp
public class SampleDao : ActiveRecord<SampleDao>
{
    public override string tableName { get { return "SampleTable"; } }
    public override string primaryKey { get { return "sample_dao_id"; } }

    public int param_int { get { return GetInt("param_int"); } set { this["param_int"] = value; } }
    public string param_string { get { return GetString("param_string"); } set { this["param_string"] = value; } }
    public bool param_bool { get { return GetBool("param_bool"); } set { this["param_bool"] = value; } }
}
```


新規で作るクラスは `ActiveRecord<T>` を継承しないといけません、
`tableName` は対象のテーブル名を入れます。
`primaryKey` はプライマリキーとなっているカラム名を入れてください。NattoはこのプロパティをキーとしてSQLを生成します。

レコードの値は、`this["カラム名"]` の形式で取り出したり設定ができます。
ただ、すべてobject型で格納されているので利用する場合は下記メソッドを使ってそれぞれの型に変換して取り出したほうが良いです。

```csharp
GetInt(key)          // => int型で取得
GetIntOrNull(key)    // => NULLもしくはint型で取得
GetFloat(key)        // => float型で取得
GetFloatOrNull(key)  // => NULLもしくはfloat型で取得
GetString(key)       // => string型で取得
```

基本的には、サンプルのようにプロパティで隠蔽するような書き方を想定しています。

## DB操作
### 取得
LINQ的な感じで取得できます

```csharp
SampleDao dao = SampleDao.Find(n => n.param_string == "okame"); // カラム名 param_string が okame のレコードを取得する

List<SampleDao> manyDao = SampleDao.FindAll(); // テーブルの全レコード取得

List<SampleDao> whereDao = SampleDao.Where(n => n.param_int > 60); // カラム名 param_int が 60以上のレコードだけ取得

```

### 作成


```csharp
SampleDao dao = new SampleDao { foo = "foo", bar = "bar" };
SampleDao.Create(dao); // => Void
```

### 更新

```csharp
SampleDao dao = SampleDao.Find(n => n.id == 2);
dao.param_int = 100;
SampleDao.Update(dao); // => Void
```

### 削除

```csharp
SampleDao dao = SampleDao.Find(n => n.id == 2);
SampleDao.Delete(dao);
```

## 注意点
### 全レコード取ってきてる
内部的には、FindAllで一旦全レコード持ってきてリストに保持しておき、それをその都度LINQで取り出しているだけです。
なので10万件とか100万件とかあるテーブルだと大変なことになります。

これは、小規模なDBでの利用のために作ったからです。(RPGの武器とかアイテムとかの各データ保持するとかそんなレベル)
あくまでExcelの代わりレベルでの利用を想定しています。
あとLINQを使いたかったからです。

### SQLiteでパスワードが設定できない

だいたいこの記事に全て書かれていますが、利用しているdllが `Mono.Data.SQlite` なのでパスワード設定ができません。
https://sites.google.com/site/nrapmed/unityrepo/unisqlite

`System.Data.SQLite` はWindows限定なので、Macの自分には厳しく断念しました。
データの改造は自己責任でということで・・。

## 作ってみて

外側だけActiveRecordの丸パクリみたいなことしたけど、割と便利だった。
OSSなので、使っていてこうしたらいいのでは、などがありましたら修正してプルリクなど
送ってもらえると喜びます。

## おまけ

無料でSQLite扱えるアセットが出ていました。
https://www.assetstore.unity3d.com/jp/#!/content/20660
これ使った方がみんな幸せになれそう