LoginSignup
4
9

More than 3 years have passed since last update.

[Android] Room (SQLite) でテーブルからビューを生成する

Last updated at Posted at 2020-05-14

はじめに

SQLite のラッパーライブラリである Room を利用して、あるテーブルからビューを生成してみたいと思います。今回は 2つのテーブルから、1つのビューを生成しようと思います。次のような User と Repo という 2つのテーブルを作成し、そこから UserRepo という 1つのビューを生成する感じのものです。

Image from Gyazo
※ ビューを生成するだけために UserId を主キーとする User と Repo のテーブルを定義してます。内容に関しては意味があるわけではありません。

準備

Roomのセットアップ方法は[Android]Roomを使ったサンプルと解説 で紹介していますので参考にしてセットアップします。

実装

User テーブルを作成する

User 情報のためのテーブルを users というテーブル名称で作成します。 User は主キーとして ID を持ち、その他に FirstName や LastName を持つユーザー情報になります。

User.kt

@Entity(tableName = "users")
data class User(
    @PrimaryKey(autoGenerate = false) val id: Int,
    val firstName: String?,
    val lastName: String?
)

テーブルの操作には Dao が必要になります。なので Insert, Update, Delete, DeleteAll, GetAll を備えた標準的な Dao を定義します。

UserDao.kt

@Dao
interface UserDao {
    @Insert
    fun insert(user : User)

    @Update
    fun update(user : User)

    @Delete
    fun delete(user : User)

    @Query("delete from users")
    fun deleteAll()

    @Query("select * from users")
    fun getAll(): List<User>

    @Query("select * from users where id = :id")
    fun getUser(id: Int): User
}

Repo テーブルを作成する

Repo 情報のためのテーブルを repos というテーブル名称で作成します。 Repo は主キーとして User のID を持ち、その他に Name を持つレポジトリ情報になります。

Repo

@Entity(tableName = "repos")
data class Repo(
    @PrimaryKey val userId: Int,
    val name: String?
)

テーブルの操作には Dao が必要になります。なので Insert, Update, Delete, DeleteAll, GetAll を備えた標準的な Dao を定義します。

RepoDao.kt

@Dao
interface RepoDao {
    @Insert
    fun insert(repo : Repo)

    @Update
    fun update(repo : Repo)

    @Delete
    fun delete(repo : Repo)

    @Query("delete from repos")
    fun deleteAll()

    @Query("select * from repos")
    fun getAll(): List<Repo>

    @Query("select * from repos where userId = :userId")
    fun getRepo(userId: Int): Repo
}

UserRepo ビューを生成する

users と repos テーブルから UserRepo ビューを作成していきます。Room でビューを作成するには @DatabaseView をつけ、viewName にはビュー名称、value にはどのようなビューを生成するのか記述した SQL 文を記述します。

SQL記述の際に気をつけること

  • SQL 文に含めるデーブル名称は、各テーブルの定義で指定した名称にする
  • SELECT で指定した属性名、クラスで定義したプロパティ名が一致しなければならない。
@DatabaseView(
    viewName = "UserRepo",
    value = """
        SELECT users.id, users.lastName, users.firstName,
        repos.name AS repoName FROM users
        INNER JOIN repos ON users.id = repos.userId
    """
)
data class UserRepo(
    val id: Int,
    val lastName: String?,
    val firstName: String?,
    val repoName: String?
)

ビューを操作するにも Dao が必要になります。ビューを操作する Dao では
@Insert@Delete@Update などは使えません。そのため全て @Query で操作を記述する必要があります。今回は GetAll と GetUserRepo という単純な操作を定義しました。

@Dao
interface UserRepoDao {
    @Query("select * from UserRepo")
    fun getAll(): List<UserRepo>

    @Query("select * from UserRepo where id = :id")
    fun getUserRepo(id: Int): UserRepo
}

RoomDatabase を作成する

定義したテーブルとビューを操作するには RoomDatabase を実装したクラスが必要です。RoomDatabase の実装でやらなければいけないことは 2つです。

1つ目ですが、@Databse アノテーションをつける必要があります。@Database アノテーションを付け、entities には利用するテーブル、 views には利用するビューを指定してやります。

2つ目ですが テーブルとビューを操作する Dao を取得するメソッドを実装する必要があります。実装ですが簡単で Dao を戻り値とする関数を定義するだけです。

@Database(entities = [User::class, Repo::class], views = [UserRepo::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
    abstract fun repoDao(): RepoDao
    abstract fun userRepoDao(): UserRepoDao
}

これで RoomDatabase の定義が終わり、テーブルとビューを操作できるようになりました。

動作確認

実装が終わったのであとは動作確認してみましょう。定義した RoomDatabase を初期化し、それぞれのテーブルやビューの Dao を取得します。そして新たに User と Repo の情報をテーブルに追加した上で、UserRepo ビューから取得してみます。

class MainActivity : AppCompatActivity() {
    private val database : AppDatabase by lazy {
        Room.databaseBuilder(applicationContext, AppDatabase::class.java, "database-name"
        ).fallbackToDestructiveMigration().build()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        CoroutineScope(Dispatchers.IO).launch {
            testForUserRepo()
        }
    }

    private fun testForUserRepo() {
        val userDao = database.userDao()
        val repoDao = database.repoDao()
        val userRepoDao = database.userRepoDao()

        val newUser = User(0, Date().time.toString(), Date().time.toString())
        val newRepo = Repo(newUser.id, Date().time.toString())

        userDao.insert(newUser)
        repoDao.insert(newRepo)
        Log.v("TAG", "get view ${userRepoDao.getAll()}")

        userDao.delete(newUser)
        repoDao.delete(newRepo)
        Log.v("TAG", "get view ${userRepoDao.getAll()}")
    }
}

実行すると意図したとおり、 User と Repo があわさった UserRepo が取得できました。

V/TAG: get view [UserRepo(id=0, lastName=1589440137149, firstName=1589440137149, repoName=1589440137160)]
V/TAG: get view []

おわりに

Room でもビューは定義できました。説明した通りテーブルといくつか異なる点があるので注意が必要ですね。作成したコードは下記に保存しているので興味があれば閲覧してみてください。

参考文献

4
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
9