nirasan's tech blog

趣味や仕事の覚え書きです。Linux, Perl, PHP, Ruby, Javascript, Android, Cocos2d-x, Unity などに興味があります。

Unity で Parse.com を使う - オブジェクトの CRUD 編

登録

GameScore クラスのオブジェクトを作成する
// オブジェクトの作成
ParseObject gameScore = new ParseObject("GameScore");
// カラムにデータの登録
gameScore["score"] = 1337;
gameScore["playerName"] = "Sean Plott";
// 非同期で保存
Task saveTask = gameScore.SaveAsync();
カラムのデータ型
// Number (int, float, double, long)
int number = 42;
// String
string str = "the number is " + number;
// DateTime
DateTime date = DateTime.Now;
// byte[]
byte[] data = System.Text.Encoding.UTF8.GetBytes("foo");
// IList<T>
IList<object> list = new List<object> { str, number };
// IDictionary<string, T>
IDictionary<string, object> dictionary = new Dictionary<string, object>
{
    { "number", number },
    { "string", str }
};
 
var bigObject = new ParseObject("BigObject");
bigObject["myNumber"] = number;
bigObject["myString"] = str;
bigObject["myDate"] = date;
bigObject["myData"] = data;
bigObject["myList"] = list;
bigObject["myDictionary"] = dictionary;
Task saveTask = bigObject.SaveAsync();

検索

objectIDで検索
// クラスを指定してクエリの作成
ParseQuery<ParseObject> query = ParseObject.GetQuery("GameScore");
// objectID を指定して非同期で検索
query.GetAsync("xWMyZ4YEGZ").ContinueWith(t =>
{
    // 検索結果から ParseObject を取得
    ParseObject gameScore = t.Result;
});
ParseObject からカラムの値の取得
// カラム名と型を指定して値を取得する
int score = gameScore.Get<int>("score");
string playerName = gameScore.Get<string>("playerName");
bool cheatMode = gameScore.Get<bool>("cheatMode");

// いろいろな型の取得サンプル
ParseObject bigObject = t.Result;
int number = bigObject.Get<int>("myNumber");
string str = bigObject.Get<string>("myString");
DateTime date = bigObject.Get<DateTime>("myDate");
byte[] data = bigObject.Get<byte[]>("myData");
IList<object> list = bigObject.Get<List<object>>("myList");
IDictionary<string, object> dictionary = bigObject.Get<Dictionary<string, object>>("myDictionary");
Debug.Log ("Number: " + number);
Debug.Log ("String: " + str);
Debug.Log ("Date: " + date);
string dataString = System.Text.Encoding.UTF8.GetString(data, 0, data.Length);
Debug.Log ("Data: " + dataString);
foreach (var item in list) {
    Debug.Log ("Item: " + item.ToString());
}
foreach (var key in dictionary.Keys) {
    Debug.Log ("Key: " + key + " Value: " + dictionary[key].ToString());
}
取得済みの ParseObject の最新の値を取得する
Task<ParseObject> fetchTask = myObject.FetchAsync();

更新

// ParseObject の作成
var gameScore = new ParseObject("GameScore")
{
    { "score", 1337 },
    { "playerName", "Sean Plott" },
    { "cheatMode", false },
    { "skills", new List<string> { "pwnage", "flying" } },
};
gameScore.SaveAsync().ContinueWith(t =>
{
    // 作成直後に更新
    gameScore["cheatMode"] = true;
    gameScore["score"] = 1338;
    gameScore.SaveAsync();
});

削除

Task deleteTask = myObject.DeleteAsync();

もっと検索

リストの取得
// 検索条件を指定してクエリの作成
var query = ParseObject.GetQuery("GameScore")
    .WhereEqualTo("playerName", "Dan Stemkoski");
// 非同期でリストの取得
query.FindAsync().ContinueWith(t =>
{
    IEnumerable<ParseObject> results = t.Result;
});
1件取得
var query = ParseObject.GetQuery("GameScore")
    .WhereEqualTo("playerEmail", "dstemkoski@example.com");
query.FirstAsync().ContinueWith(t =>
{
    ParseObject obj = t.Result;
});
並び替え
var query = ParseObject.GetQuery("GameScore")
    .OrderBy("score")
    .ThenByDescending("playerName");
検索条件で OR を使う
var lotsOfWins = ParseObject.GetQuery("Player")
    .WhereGreaterThan("wins", 150);
 
var fewWins = ParseObject.GetQuery("Player")
    .WhereLessThan("wins", 5);
 
ParseQuery<ParseObject> query = lotsOfWins.Or(fewWins);

非同期処理のコントロール

  • 登録、更新、検索、削除と、どの操作をする場合も、処理は非同期となり、返り値の System.Threading.Tasks.Task オブジェクトを扱うことで、結果の取得や終了後の処理などをコントロールできる。
ContinueWith メソッドで結果を扱う
obj.SaveAsync().ContinueWith(task =>
{
    if (task.IsCanceled)
    {
        // 登録がキャンセルされた場合の処理
    }
    else if (task.IsFaulted)
    {
        // 登録が失敗した場合
        AggregateException exception = task.Exception;
    }
    else
    {
        // 登録が成功した場合
    }
});
ContinueWith の連鎖
  • ContinueWith に渡した無名関数の中で、Task を return することで、非同期処理終了後に別の非同期処理を開始することができる。
  • Unwrap() はおまじない。ContinueWith の返り値の Task> を Task に変換する。
var query = new ParseQuery<ParseObject>("Student")
    .OrderByDescending("gpa");
 
query.FindAsync().ContinueWith(t =>
{
    var students = t.Result;
    IEnumerator<ParseObject> enumerator = students.GetEnumerator();
    enumerator.MoveNext();
    var student = enumerator.Current;
    student["valedictorian"] = true;
    return student.SaveAsync();
}).Unwrap().ContinueWith(t =>
{
    return query.FindAsync();
}).Unwrap().ContinueWith(t =>
{
    var students = t.Result;
    IEnumerator<ParseObject> enumerator = students.GetEnumerator();
    enumerator.MoveNext();
    enumerator.MoveNext();
    var student = enumerator.Current;
    student["salutatorian"] = true;
    return student.SaveAsync();
}).Unwrap().ContinueWith(t =>
{
    // Everything is done!
});
空のタスクの作成
  • タスクの連鎖中などに使いたくなるかも
// FindAsync 結果のタスクのダミー
var task = Task.FromResult<IEnumerable<ParseObject>>(new List<ParseObject>());
結果の描画
  • FindAsync などで取得した ParseObject の値を使って GameObject などを作成する場合、ContinueWith の無名関数の中では直接 Instaitiate などできない。
  • そこで FindAsync などの結果は一度プロパティなどに保存し、Update でプロパティに値が入っていたら描画をする、という流れで取得したデータを描画する。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Parse;

private List<ParseObject> parseObjectList = null;

void Start () {
    var query = ParseObject.GetQuery("GameScore")
        .WhereEqualTo("playerName", "Dan Stemkoski");
    query.FindAsync().ContinueWith(t =>
    {
        parseObjectList = new List<ParseObject> (t.Result);
    });
}

void Update () {
    if (parseObjectList != null) {
        foreach (var obj in parseObjectList) {
            // GameObject の作成など
        }
        parseObjectList = null;
    }
}