Room을 사용하여 투영 처리
개요
Android & Room에서 투영을 처리하는 방법을 말씀드리겠습니다.Room이 무엇인지 Room이 어떻게 사용되는지에 대한 자세한 내용은 다른 글을 참조하십시오.
구상된 응용 프로그램
청공 라이브러리 뷰어
기능
Book
표현서 반이야.원래 Primary Key는 ISDN을 사용해야 하는지, title과 author의 복합 키를 사용해야 하는지 등을 사용해야 했지만 이번에는 사랑을 끊었다.
@Entity
class Book {
/** 本の名前 */
@PrimaryKey
var title: String = ""
/** 本の中身 */
var content: String = ""
/** いつ読んだか */
var lastRead: Long = 0L
/** どこまで読んだか */
var markIndex: Int = 0
}
Dao
책의 일람을 표시하는 데 사용되는 getall, 클릭한 책의 내용을 표시하기 위해 내용을 가져오는 findContentByTitle을 정의합니다.
@Dao
interface BookRepository {
@Query("SELECT * FROM book ORDER BY lastRead DESC LIMIT 500")
fun getAll(): List<Book>
@Query("SELECT content FROM book WHERE title = :title LIMIT 1")
fun findContentByTitle(title: String): String?
}
모든 열을 꺼내는 데 무슨 문제가 있습니까?
위의 Book 객체를 RecyclerView에서 처리하면 스크롤이 매우 무거워집니다.
그림과 같은 책의 일람을 표시할 때 책의 내용이 필요하지 않습니다.콘텐츠에 커다란 데이터가 있기 때문에 상세한 페이지를 열 때마다 읽으면 충분합니다.따라서 Dao의 getall 메서드는 콘텐츠를 추출할 필요가 없습니다.
룸으로 사영을 처리할 수 있습니까?
투영
관계 데이터베이스 테이블에서 일부 열의 작업을 검색합니다.물론 SQLite에서 SELECT에 열을 지정하면 투영을 체크 아웃할 수도 있습니다.
검색할 열이 하나만 있는 경우 @Query SELECT 에서 열을 지정하고 해당 유형을 반환 값의 유형으로 지정할 수 있습니다.
룸 투영
다음 예제에서는 여러 행을 읽어들이고 목록에 지정합니다.@Dao
interface BookRepository {
@Query("SELECT content FROM book")
fun getAllBookTitles(): List<String>
룸으로 투영?
그러나 추출하려는 열이 2개 이상인 경우 예를 들어 Pair 등을 사용해도 제대로 매핑되지 않습니다.@Dao
interface BookRepository {
@Query("SELECT title, last_read FROM book")
fun getAllBookForList(title: String): List<Pair<String, Long>>
다음 컴파일 오류를 내보냅니다.エラー: Not sure how to convert a Cursor to this method's return type
이 오류를 보면 Cursor라면 비추기 때문에 Cursor로 받아서 사용하는 것도 방법이겠죠.예전부터 익숙했던 방법으로 처리할 수 있다.다만, Cursor의 경우 어렵게 Room을 사용한다는 의미가 희미해지기 때문에 다른 방법을 찾아보고 싶습니다.
문외한으로 Room은 SQL에 문제가 있을 때 컴파일이 잘못된 형식으로 지적하는 것이 가장 좋다.
그럼 어떡하지?
투영을 나타내는 데이터 클래스를 정의하고 이를 Dao의@Query 함수의 반환값 유형으로 지정하면 투영을 검색할 수 있습니다.
투영 클래스
투영으로 읽어들일 열과 같은 이름과 형식을 가진 데이터 클래스를 정의합니다.data class BookListItem(
val title: String,
val lastRead: Long
val markIndex: Int
)
테이블의 열 이름이 다른 필드 이름을 가지려면 @ColumnInfo 에서 열 이름을 지정합니다.import androidx.room.ColumnInfo
data class BookListItem(
@ColumnInfo(name = "title") val bookTitle: String,
@ColumnInfo(name = "lastRead") val bookLastRead: Long
@ColumnInfo(name = "markIndex") val markedIndex: Int
)
Dao 수정
그런 다음 Dao의 반환 값 유형에 투영된 데이터 클래스를 지정합니다.@Dao
interface BookRepository {
@Query("SELECT title, lastRead, markIndex FROM book")
fun getAllBookForList(): List<BookListItem>
이렇게 하면 방에서 투영을 처리할 수 있다.
Room 생성 코드
Room에서는 SQLite를 사용하여 코드를 자동으로 생성합니다.실제로 어떤 코드가 만들어졌는지 보면 Room에서 사용할 수 없는 환경에서 SQLite에 접근하는 코드를 써야 할 때 유용하다.하지만 Room을 사용할 수 있도록 노력하면 앞으로의 효율이 더욱 좋아질 수 있습니다 @Override
public List<BookListItem> getAllBookForList() {
final String _sql = "SELECT title, lastRead, markIndex FROM book";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
final Cursor _cursor = __db.query(_statement);
try {
final int _cursorIndexOfTitle = _cursor.getColumnIndexOrThrow("title");
final int _cursorIndexOfLastRead = _cursor.getColumnIndexOrThrow("lastRead");
final int _cursorIndexOfMarkedIndex = _cursor.getColumnIndexOrThrow("markIndex");
final List<BookListItem> _result = new ArrayList<BookListItem>(_cursor.getCount());
while(_cursor.moveToNext()) {
final BookListItem _item;
final String _tmpTitle;
_tmpTitle = _cursor.getString(_cursorIndexOfTitle);
final long _tmpLastRead;
_tmpLastRead = _cursor.getLong(_cursorIndexOfLastRead );
final int _tmpMarkedIndex;
_tmpMarkedIndex = _cursor.getInt(_cursorIndexOfMarkedIndex);
_item = new BookListItem(_tmpTitle,_tmpLastRead,_tmpMarkedIndex);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
_statement.release();
}
}
룸이 자동으로 이런 정형 코드를 생성할 수 있다는 것을 알면 가져올 때도 쉽게 설득할 수 있다.
총결산
Android와 Room을 사용하여 SQLite 처리를 수행할 때 테이블의 일부만 필요하면 투영 클래스에서 열을 정의하여 투영을 읽어들일 수 있습니다.
그러나 이번 경우처럼 거대한 값을 열의 하나로 SQLite에 넣는 것보다 다른 방법을 취하는 것이 좋다.예를 들어, 이미지를 처리하는 경우 이미지는 응용 프로그램에 파일로 저장되고 SQLite에서는 참조 목적지에만 저장됩니다.이렇게 하면 몇 GB의 데이터를 SQLite에 잘못 넣어 성능에 치명적인 악영향을 끼칠 염려가 없다.
"표를 정규화하면 되지 않나요?"그렇게 생각하지만 Android & SQLite에서 정규화되면 퍼포먼스가 없을 거예요.나 혼자 안 해봤어.
참고 자료
@Dao
interface BookRepository {
@Query("SELECT content FROM book")
fun getAllBookTitles(): List<String>
@Dao
interface BookRepository {
@Query("SELECT title, last_read FROM book")
fun getAllBookForList(title: String): List<Pair<String, Long>>
エラー: Not sure how to convert a Cursor to this method's return type
투영을 나타내는 데이터 클래스를 정의하고 이를 Dao의@Query 함수의 반환값 유형으로 지정하면 투영을 검색할 수 있습니다.
투영 클래스
투영으로 읽어들일 열과 같은 이름과 형식을 가진 데이터 클래스를 정의합니다.
data class BookListItem(
val title: String,
val lastRead: Long
val markIndex: Int
)
테이블의 열 이름이 다른 필드 이름을 가지려면 @ColumnInfo 에서 열 이름을 지정합니다.import androidx.room.ColumnInfo
data class BookListItem(
@ColumnInfo(name = "title") val bookTitle: String,
@ColumnInfo(name = "lastRead") val bookLastRead: Long
@ColumnInfo(name = "markIndex") val markedIndex: Int
)
Dao 수정
그런 다음 Dao의 반환 값 유형에 투영된 데이터 클래스를 지정합니다.
@Dao
interface BookRepository {
@Query("SELECT title, lastRead, markIndex FROM book")
fun getAllBookForList(): List<BookListItem>
이렇게 하면 방에서 투영을 처리할 수 있다.Room 생성 코드
Room에서는 SQLite를 사용하여 코드를 자동으로 생성합니다.실제로 어떤 코드가 만들어졌는지 보면 Room에서 사용할 수 없는 환경에서 SQLite에 접근하는 코드를 써야 할 때 유용하다.하지만 Room을 사용할 수 있도록 노력하면 앞으로의 효율이 더욱 좋아질 수 있습니다 @Override
public List<BookListItem> getAllBookForList() {
final String _sql = "SELECT title, lastRead, markIndex FROM book";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
final Cursor _cursor = __db.query(_statement);
try {
final int _cursorIndexOfTitle = _cursor.getColumnIndexOrThrow("title");
final int _cursorIndexOfLastRead = _cursor.getColumnIndexOrThrow("lastRead");
final int _cursorIndexOfMarkedIndex = _cursor.getColumnIndexOrThrow("markIndex");
final List<BookListItem> _result = new ArrayList<BookListItem>(_cursor.getCount());
while(_cursor.moveToNext()) {
final BookListItem _item;
final String _tmpTitle;
_tmpTitle = _cursor.getString(_cursorIndexOfTitle);
final long _tmpLastRead;
_tmpLastRead = _cursor.getLong(_cursorIndexOfLastRead );
final int _tmpMarkedIndex;
_tmpMarkedIndex = _cursor.getInt(_cursorIndexOfMarkedIndex);
_item = new BookListItem(_tmpTitle,_tmpLastRead,_tmpMarkedIndex);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
_statement.release();
}
}
룸이 자동으로 이런 정형 코드를 생성할 수 있다는 것을 알면 가져올 때도 쉽게 설득할 수 있다.
총결산
Android와 Room을 사용하여 SQLite 처리를 수행할 때 테이블의 일부만 필요하면 투영 클래스에서 열을 정의하여 투영을 읽어들일 수 있습니다.
그러나 이번 경우처럼 거대한 값을 열의 하나로 SQLite에 넣는 것보다 다른 방법을 취하는 것이 좋다.예를 들어, 이미지를 처리하는 경우 이미지는 응용 프로그램에 파일로 저장되고 SQLite에서는 참조 목적지에만 저장됩니다.이렇게 하면 몇 GB의 데이터를 SQLite에 잘못 넣어 성능에 치명적인 악영향을 끼칠 염려가 없다.
"표를 정규화하면 되지 않나요?"그렇게 생각하지만 Android & SQLite에서 정규화되면 퍼포먼스가 없을 거예요.나 혼자 안 해봤어.
참고 자료
@Override
public List<BookListItem> getAllBookForList() {
final String _sql = "SELECT title, lastRead, markIndex FROM book";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
final Cursor _cursor = __db.query(_statement);
try {
final int _cursorIndexOfTitle = _cursor.getColumnIndexOrThrow("title");
final int _cursorIndexOfLastRead = _cursor.getColumnIndexOrThrow("lastRead");
final int _cursorIndexOfMarkedIndex = _cursor.getColumnIndexOrThrow("markIndex");
final List<BookListItem> _result = new ArrayList<BookListItem>(_cursor.getCount());
while(_cursor.moveToNext()) {
final BookListItem _item;
final String _tmpTitle;
_tmpTitle = _cursor.getString(_cursorIndexOfTitle);
final long _tmpLastRead;
_tmpLastRead = _cursor.getLong(_cursorIndexOfLastRead );
final int _tmpMarkedIndex;
_tmpMarkedIndex = _cursor.getInt(_cursorIndexOfMarkedIndex);
_item = new BookListItem(_tmpTitle,_tmpLastRead,_tmpMarkedIndex);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
_statement.release();
}
}
Android와 Room을 사용하여 SQLite 처리를 수행할 때 테이블의 일부만 필요하면 투영 클래스에서 열을 정의하여 투영을 읽어들일 수 있습니다.
그러나 이번 경우처럼 거대한 값을 열의 하나로 SQLite에 넣는 것보다 다른 방법을 취하는 것이 좋다.예를 들어, 이미지를 처리하는 경우 이미지는 응용 프로그램에 파일로 저장되고 SQLite에서는 참조 목적지에만 저장됩니다.이렇게 하면 몇 GB의 데이터를 SQLite에 잘못 넣어 성능에 치명적인 악영향을 끼칠 염려가 없다.
"표를 정규화하면 되지 않나요?"그렇게 생각하지만 Android & SQLite에서 정규화되면 퍼포먼스가 없을 거예요.나 혼자 안 해봤어.
참고 자료
Reference
이 문제에 관하여(Room을 사용하여 투영 처리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/toastkidjp/items/44f5fec99c15884f86cf텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)