@Entity(tableName = "product")
public class Product {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
public int mId;
public String name;
public int price;
@Ignore
public Bitmap picture;
}
@Entity(tableName = "product")
public class Product {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
private int mId;
private String name;
private int price;
@Ignore
private Bitmap picture;
public Product(int id, String name, int price
, Bitmap picture) {
mId = id;
this.name = name;
this.price = price;
this.picture = picture;
}
}
@Dao
public interface ProductDao {
@Insert
void insertProducts(Product... product);
@Update
void updateProducts(Product... product);
@Delete
void deleteProducts(Product... product);
@Query("SELECT * FROM product")
List<Product> getAllProducts();
}
@Query("SELECT * FROM product WHERE id IS :id")
Product getProductWithId(int id);
@Query("SELECT * FROM product WHERE name IS (:names)")
List<Product> getProductsWithName(List<String> names);
public class ProductMainInfo {
public int price;
public String name;
}
@Query("SELECT name,price FROM product WHERE id IS :id")
ProductMainInfo getProductMainInfoWithId(int id);
@Insert
void insertProducts(Product... product);
@Update
void updateProducts(Product... product);
@Delete
void deleteProducts(Product... product);
@Query("SELECT * FROM product")
List<Product> getAllProducts();
@Query("SELECT name,price FROM product WHERE id IS :id")
ProductMainInfo getProductMainInfoWithId(int id);
@Query("SELECT * FROM prduct WHRER id = :id")
LiveData<Product> getProductById(int id);
@Query("SELECT * FROM prduct WHERE id = :id")
Flowable<Product> getProductById(int id);
background
thread
main
thread
observOn
(Scheduler)
product
product
getProductById(int id);
LiveData<Product>
Flowable<Product>
@Insert
void insertProducts(Product... product);
@Update
void updateProducts(Product... product);
@Delete
void deleteProducts(Product... product);
@Query("SELECT * FROM product")
List<Product> getAllProducts();
@Query("SELECT name,price FROM product WHERE id IS :id")
ProductMainInfo getProductMainInfoWithId(int id);
@Dao
public abstract class ProductDao {
@Insert
abstract void insertProducts(Product... product);
@Delete
abstract deleteProducts(Product... product);
@Transaction
public void replaceProducts(Products[] oldProducts
, Products[] newProducts){
deleteProducts(oldProducts);
insertProducts(newProducts);
}
}
@Database(entities = {Product.class}, version = 1)
public abstract class StoreDatabase extends RoomDatabase {
}
public abstract ProductDao productDao();
private static final String DB_NAME = "store";
private static volatile StoreDatabase INSTANCE;
public static StoreDatabase getInstance(Context context) {
synchronized (StoreDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context,
StoreDatabase.class, DB_NAME)
.build();
}
return INSTANCE;
}
}
//initialize StoreDatabase
StoreDatabase db = StoreDatabase.getInstance(this);
//insert a product
db.productDao().insertProducts(new Product("water",3000));
//retrieve inserted product
List<Product> products = db.productDao().getAllProducts();
disposable = db.productDao().getProductById(10)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(product ->
txtResult.setText(product.getName()),
throwable ->
Log.e("db", "Unable to get productName", throwable));
//onStop
disposable.dispose();
db.productDao().getProductById(10)
.observe(this, new Observer<Product>() {
@Override
public void onChanged(@Nullable Product product) {
if (product != null) {
txtResult.setText(product.getName());
} else {
txtResult.setText("data is not available!");
}
}
});
@RunWith(AndroidJUnit4.class)
public class ProductDaoTest {
private StoreDatabase database;
private ProductDao productDao;
private Product PRODUCT = new Product(10, "soda");
@Before
public void initDb() throws Exception {
database = Room.inMemoryDatabaseBuilder(
InstrumentationRegistry.getContext(),
StoreDatabase.class)
.build();
productDao = database.productDao();
}
@After
public void closeDb() throws Exception {
database.close();
}
@Test
public void productCanBeRetrievedAfterInsert() throws Exception {
//insert a product
productDao.insertProducts(PRODUCT);
//get inserted product by id
Product actual = productDao
.getProductWithId(PRODUCT.getId());
//Test
assertEquals(PRODUCT.getId(), actual.getId());
assertEquals(PRODUCT.getName(), actual.getName());
}
}
@Rule
public InstantTaskExecutorRule instantTaskExecutorRule
= new InstantTaskExecutorRule();
@Test
public void productCanBeRetrievedAfterInsertWithLiveData()
throws Exception {
//insert a product
productDao.insertProducts(PRODUCT);
//get inserted product by id using LiveData
LiveData<Product> actual = productDao
.getProductWithIdByLiveData(PRODUCT.getId());
//getData from LiveData
Product actualProduct = LiveDataTestUtil.getValue(actual);
//Test
assertEquals(PRODUCT.getId(), actualProduct.getId());
assertEquals(PRODUCT.getName(), actualProduct.getName());
}
@Test
public void productCanBeRetrievedAfterInsertWithRXJava()
throws Exception {
//insert a product
productDao.insertProducts(PRODUCT);
//get inserted product by id using Flowable
productDao
.getProductWithIdByRxJava(PRODUCT.getId())
.test().assertValue(actualProduct ->
actualProduct.getId() == PRODUCT.getId()
&& actualProduct.getName()
.equals(PRODUCT.getName()));
}
public class BitmapConverter {
@TypeConverter
public Bitmap toBitmap(byte[] byteArray) {
return BitmapFactory
.decodeByteArray(byteArray, 0, byteArray.length);
}
@TypeConverter
public byte[] toByteArray(Bitmap bitmap) {
ByteArrayOutputStream stream =
new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG
, 100, stream);
return stream.toByteArray();
}
}
@Database(entities = {Product.class}, version = 2)
@TypeConverters(BitmapConverter.class)
public abstract class StoreDatabase extends RoomDatabase {
....
}
@Entity(tableName = "product")
public class Product {
...
@ColumnInfo(typeAffinity = ColumnInfo.BLOB)
private Bitmap picture;
...
}
@Entity(tableName = "user")
public class User {
@PrimaryKey(autoGenerate = true)
private int id;
private String identityNumber;
private String name;
}
@Entity(tableName = "simcard",
foreignKeys = @ForeignKey(entity = User.class,
parentColumns = "id",
childColumns = "userId",
onDelete = CASCADE))
public class SimCard {
@PrimaryKey(autoGenerate = true)
private int id;
private String number;
private String serial;
private int userId;
}
public interface SimCardDao {
....
@Query("SELECT * FROM SimCard WHERE userId=:userId")
List<SimCard> getSimCardsOfUser(final int userId);
}
@Entity(tableName = "author")
public class Author {
@PrimaryKey(autoGenerate = true)
private int id;
private String name;
private String identityId;
....
}
@Entity(tableName = "book")
public class Book {
@PrimaryKey(autoGenerate = true)
private int id;
private String name;
private String ISBN;
....
}
@Entity(tableName = "author_book_join",
primaryKeys = {"authorId", "bookId"},
foreignKeys = {
@ForeignKey(entity = Author.class,
parentColumns = "id",
childColumns = "authorId"),
@ForeignKey(entity = Book.class,
parentColumns = "id",
childColumns = "bookId")
})
public class AuthorBookJoin {
private int authorId;
private int bookId;
....
}
public interface AuthorBookJoinDao {
@Insert
void insertAuthorBookJoin(AuthorBookJoin authorBookJoin);
@Update
void updateAuthorBookJoin(AuthorBookJoin authorBookJoin);
@Delete
void deleteAuthorBookJoin(AuthorBookJoin authorBookJoin);
@Query("SELECT * FROM author INNER JOIN author_book_join " +
"ON author.id = author_book_join.authorId " +
"WHERE author_book_join.bookId =:bookId")
List<Author> getAuthorsForBook(final int bookId);
@Query("SELECT * FROM book INNER JOIN author_book_join " +
"ON book.id = author_book_join.bookId " +
"WHERE author_book_join.authorId =:authorId")
List<Book> getBooksForAuthor(final int authorId);
}
//insertAuthor
authorDao.insert(new Author(1,
"Robert Cecil Martin",
"135491354"));
//insertbook
bookDao.insert(new Book(1,
"Clean Code",
"9785459008586"));
//insertJoin
authorBookJoinDao.insert(new AuthorBookJoin(1, 1));
//get list of Authors of a book
List<Author> authors = authorBookJoinDao.getAuthorsForBook(1);
//get list of books of an Author
List<Book> books = authorBookJoinDao.getBooksForAuthor(1);
@Entity(tableName = "product")
public class Product {
...
@ColumnInfo(typeAffinity = ColumnInfo.BLOB)
private Bitmap picture;
...
}
@Database(entities = {Product.class}, version = 2)
@TypeConverters(BitmapConverter.class)
public abstract class StoreDatabase extends RoomDatabase {
public static StoreDatabase getInstance(Context context) {
synchronized (StoreDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context,
StoreDatabase.class, DB_NAME)
.addMigrations(MIGRATION_1_2)
.build();
}
return INSTANCE;
}
}
public static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE product ADD COLUMN picture BLOB");
}
};
}
.adddMigrations(MIGRATION_1_2,
MIGRATION_2_3,
MIGRATION_3_4,
MIGRATION_4_5,
MIGRATION_2_5)
//migration from 1 to 5
MIGRATION_1_2 -- MIGRATION_2_5
@Rule
public MigrationTestHelper mMigrationTestHelper =
new MigrationTestHelper(InstrumentationRegistry
.getInstrumentation(),
StoreDatabase.class.getCanonicalName(),
new FrameworkSQLiteOpenHelperFactory());
@Test
public void migrationFrom1To2_containsCorrectData()
throws IOException {
// Create the database in version 1
SupportSQLiteDatabase db =
mMigrationTestHelper.createDatabase(TEST_DB_NAME, 1);
// Insert some data
insertProduct(PRODUCT.getId(), PRODUCT.getName(), db);
//Prepare for the next version
db.close();
// Re-open the database with version 2 and provide MIGRATION_1_2 and
mMigrationTestHelper.runMigrationsAndValidate(TEST_DB_NAME, 2, true,
MIGRATION_1_2);
// Validate that the data was migrated properly.
Product dbProduct = getMigratedRoomDatabase()
.productDao().getProductWithId(PRODUCT.getId());
assertEquals(dbProduct.getId(), PRODUCT.getId());
assertEquals(dbProduct.getName(), PRODUCT.getName());
}