Realm Xamarinで基本的なRealmの扱いメモ

## 前提

- [これ以上説明すると分かりやすすぎるRealmをXamarinで動かす方法](http://qiita.com/shinriyo@github/items/415806e3ffbdfc59bab4)の記事を読んでいること（読んでいると話がスムーズです。）

- `Owner`クラスと`Dog`クラスが有ること。（↑の記事にあります。）
- Xamarin Studio(Community版でもOK)が入ってること。

## やること

`Dog`モデルから以下のことを行います。

- 取り出し
- id指定取り出し 
- 挿入
- id指定更新
- 全削除
- id指定削除

## 免責事項

私がこれでやりやすいと思っていただけで、これがRealmらしい書き方かは保証できません。
もし、これより正しいやり方をご存知でしたら編集リクエストやコメントでお願いします。

## Dogを修正

以前のよりも主キーの`SSN`が増えてます。
`Owner`クラスは使ってないため、Dogから消してもいいかもしれません。

### Swift版を知ってる方
Swift版と違い、Swiftでは`primaryKey()`のオーバーライドだけで主キー設定ができましたが、`[ObjectId]`のAttributeがついています。

```csharp:Dog.cs
using System;
using System.Collections.Generic;
using Realms;

namespace 自分のプロジェクト名
{
	// Define your models like regular C# classes
	public class Dog : RealmObject 
	{
		[ObjectId]
		public string SSN { get; set; }

		public string Name { get; set; }
		public int Age { get; set; }
		public Person Owner { get; set; }
	}

	public class Person : RealmObject 
	{
		public string Name { get; set; }
		public RealmList<Dog> Dogs { get; } 
	}
}
```

## コントローラを作成

<img width="294" alt="Screen Shot 2016-06-14 at 8.40.04 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/11951/401c72c4-9a32-bdca-ad6d-6208a50690ff.png">
`Dog`モデルから操作するクラスを`Scripts/Controllers/DogController.cs`に作成した。
今回、`Scripts`フォルダを作成し、その中に`Controllers`フォルダを作成しています。


```csharp:DogController.cs
using Realms;
using System.Diagnostics;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace 自分のプロジェクト名
{
	public class DogController
	{
		private Realm realm;

		public DogController ()
		{
			this.realm = Realm.GetInstance();
		}

		public void Insert(Dog newDog)
		{
			// トランザクションを用いてオブジェクトを保存・更新します.
			this.realm.Write(() =>
			{
				var id = this.Count();	
				var mydog = realm.CreateObject<Dog>();
				mydog.SSN = (id).ToString ();
				mydog.Name = newDog.Name;
				mydog.Age = newDog.Age;
			});
		}

		public void Update(string id, Dog dog)
		{
			if (this.CountById(id) == 0)
			{
				return;
			}

			var res = this.realm.All<Dog>().Where(d => d.SSN == id).Single();
			using(var trans = realm.BeginWrite())
			{
				res.Name = dog.Name;
				res.Age = dog.Age;
				res.Owner = dog.Owner;
				trans.Commit();
			}
		}

		public Dog FindById(string id)
		{
			if (this.CountById(id) == 0)
			{
				return null;
			}

			return this.realm.All<Dog>().Where(d => d.SSN == id).Single();
		}

		public Dog[] FindAll()
		{
			return this.realm.All<Dog>().ToArray();
		}

		public int Count()
		{
			return this.realm.All<Dog>().Count();
		}		

		public int CountById(string id)
		{
			return this.realm.All<Dog>().Where(d => d.SSN == id).Count();
		}

		public void DeleteAll()
		{
			// トランザクションを開始してオブジェクトを削除します.
			using (var trans = this.realm.BeginWrite())
			{
				// これはだめ.
//				foreach (var dog in realm.All<Dog>())
//				{
//					this.realm.Remove(dog);
//				}
				this.realm.RemoveAll<Dog>();
				trans.Commit();
			}
		}

		public void DeleteById(string id)
		{
			var obj = this.FindById(id);
			if (obj == null)
			{
				return; 
			}

			// Delete an object with a transaction
			using (var trans = this.realm.BeginWrite ()) {
				this.realm.Remove(obj);
				trans.Commit();
			}
		}
	}
}
```

主キーは自分でインクリメントすることになります。面倒ですが・・。自動でいいのに。

## 実行するには

### まず古いRealm消す。

以前実行した場合、Realmのデータが残っています。
手順はAndroidのエミュレータです。
アプリごと消します。
※もっといい消し方があればコメントお願いします。

**Realmファイルを消す手順です**

1. シミュレータのデスクトップのSettingsを選択
<img width="585" alt="Screen Shot 2016-06-14 at 8.45.32 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/11951/a0afbf3d-3521-fa2d-dcd3-e0554fe2b7e4.png">

2. DEVICEの中のAppsを選択
<img width="585" alt="Screen Shot 2016-06-14 at 8.45.43 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/11951/9ff8bb9a-b727-bc9f-d7e2-c8ff5b1270b1.png">

3. 該当アプリを選択
<img width="585" alt="Screen Shot 2016-06-14 at 8.45.46 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/11951/db88d013-5903-c467-da2f-27cc05ebce10.png">

4. Uninstallで消す。
<img width="585" alt="Screen Shot 2016-06-14 at 8.45.49 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/11951/d0cb14d9-175d-c7c4-2ff8-7431ba103601.png">

*注意！・・・この手順は面倒なので、もしもっと楽な方法があると思うので教えて下さい。*

このクラスは自由です。
`SetDB()`メソッドを実行しましょう。
`Dump()`メソッドは中身を出力するために記載しました。

```csharp:test.cs

		private void SetDB()
		{
			Debug.WriteLine(new string('*', 10));

			var dc = new DogController ();
			dc.DeleteAll();

			var myDog = new Dog() { Name = "一郎", Age = 10 };
			var myDog2 = new Dog() { Name = "次郎", Age = 11 };
			var myDog3 = new Dog() { Name = "三郎", Age = 12 };
			dc.Insert(myDog);
			dc.Insert(myDog2);
			dc.Insert(myDog3);

			Debug.WriteLine(new string('*', 10));

			Debug.WriteLine("count:{0}", dc.Count());
			var dogs = dc.FindAll();
			this.Dump(dogs);

			dc.DeleteById("1");
			dc.DeleteById("1");

			dogs = dc.FindAll();
			this.Dump(dogs);

			var newDog = new Dog() { Name = "ネオドッグ", Age = 22 };
			dc.Update("5", newDog);
			dogs = dc.FindAll();
			this.Dump(dogs);
		}

		private void Dump(Dog[] dogs)
		{
			// ダンプする.
			foreach (var dog in dogs)
			{
				Debug.WriteLine("id:{0}, name:{1}, age:{2}",
					dog.SSN, dog.Name, dog.Age);
				Debug.WriteLine(new string('-', 10));
			}
		}
	}
```

## 実行した時の効果。

- 一郎、次郎、三郎の犬を3匹追加。
- カウントも出してます。
- 主キー`id`は`DogConrtroller`のおかげで自動でインクリメントされます。
- id`1`を指定して、2回消しています。これはあえて実験のため。エラーにならないように対処してます。
- id`5`に対して更新しています。しかし`5`はいないので何も起こりません。id`2`の次郎や`3`の三郎に対して行えば、ネオドッグに変化するはずです。

## 次回

今回Dog限定でその都度クラスが必要なので、Genericsクラスで汎用的にできるものを作成予定です。