带领域的DAO模式

时间:2018-06-23 22:07:58

标签: java android realm

DAO如何与领域一起使用?因为在活动中尝试设置模型类的成员时会遇到异常:

  

java.lang.IllegalStateException:只能在事务内部完成更改领域数据。

我知道使用realm.executeTransaction可以解决此问题,但是我的活动中的代码不再与数据库无关,因为它将使用特定于低级数据库通信的代码。因此,如果以后我想更改数据库,则重构将花费大量时间和工作...此外,我将不得不在所有活动中处理对Realm.getDefaultInstance();

的引用。

这是我的活动代码示例

protected void onCreate(Bundle savedInstanceState)
{
    mBook = mBookDaoImpl.getBookById(bookId);
}

// Later in the code

private void saveBook(String name)
{
    mBook.setName(name);
}

这是我的模特班

public class Book extends RealmObject
{
    @Required
    @PrimaryKey
    private String id;

    private String name;

    public Book() {
    }

    public Book(String id, String name) {
        this.id = id;
        this.name = name;
    }

    // getter setter methods
}

这是我的DAO界面:

public interface BookDao
{
    List<Book> getAllBooks();

    Book getBookByIsbn(int isbn);

    void saveBook(Book book);

    void deleteBook(Book book);
}

最后是我的实现:

public class BookDaoImpl implements BookDao
{
    private static BookDaoImpl INSTANCE = null;

    private Realm mRealm;

    private BookDaoImpl()
    {
        mRealm = Realm.getDefaultInstance();
    }

    public static BookDaoImpl getInstance()
    {
        if (INSTANCE == null)
            INSTANCE = new BookDaoImpl();

        return INSTANCE;
    }

    @Override
    public List<Book> getAllBooks()
    {
        return mRealm.where(Book.class).findAll();
    }

    @Override
    public Book getBookById(String id)
    {
        return mRealm.where(Book.class).equalTo("id", id).findFirst();
    }

    @Override
    public void saveBook(final Book book)
    {
        mRealm.executeTransaction(new Realm.Transaction()
        {
            @Override
            public void execute(Realm realm)
            {
                if (book.getId() == null)
                    book.setId(UUID.randomUUID().toString());
                realm.copyToRealmOrUpdate(book);
            }
        });
    }

    @Override
    public void deleteBook(final Book book)
    {
        mRealm.executeTransaction(new Realm.Transaction()
        {
            @Override
            public void execute(Realm realm)
            {
                mRealm.where(Counter.class).equalTo("id", book.getId())
                        .findFirst()
                        .deleteFromRealm();
            }
        });
    }
}

1 个答案:

答案 0 :(得分:1)

Realm的getInstance()方法返回一个thread-local, reference counted instance which must be paired with a close() call,因此您的DAO实现可能不符合您的期望。

如果使用我专门创建的库Realm-Monarchy来简化“抽象领域”的创建,则可以像这样实现DAO:

public class BookDaoImpl implements BookDao
{
    private static BookDaoImpl INSTANCE = null;

    private Monarchy monarchy;

    private BookDaoImpl(Monarchy monarchy)
    {
        this.monarchy = monarchy;
    }

    public static BookDaoImpl getInstance(Monarchy monarchy)
    {
        if (INSTANCE == null) {
            synchronized(BookDaoImpl.class) {
                if(INSTANCE == null) {
                    INSTANCE = new BookDaoImpl(monarchy);
                }
            }
        }
        return INSTANCE;
    }

    @Override
    public List<Book> getAllBooks()
    {
        return monarchy.fetchAllCopiedSync((realm) -> realm.where(Book.class));
    }

    @Override
    public Book getBookById(final String id)
    {
        List<Book> books = monarchy.fetchAllCopiedSync((realm) -> realm.where(Book.class).equalTo("id", id));
        if(books.isEmpty()) {
            return null;
        } else {
            return books.get(0);
        }
    }

    @Override
    public void saveBook(final Book book)
    {
        monarchy.runTransactionSync((realm) -> {
            if (book.getId() == null)
                book.setId(UUID.randomUUID().toString());
            realm.insertOrUpdate(book);
        });
    }

    @Override
    public void deleteBook(final Book book)
    {
        monarchy.runTransactionSync((realm) -> {
                realm.where(Counter.class).equalTo("id", book.getId())
                        .findFirst()
                        .deleteFromRealm();
        });
    }
}

PS:如果同步返回List<T>,而不是像LiveData<List<T>>(或最初的RealmResults<T>)这样的可观察物,则会浪费很多功能/功能。