GreenDao詳解

  • 簡介
  • Dao代碼生成
  • 會話(Sessions)
  • GreenDao操作
  • 數據庫升級

簡介

這裏寫圖片描述

  GreenDao是爲android設計的對象關係映射(ORM)工具。它提供了對象到關係型數據庫SQLite的相應接口。
  它不僅使用方便,性能也很出衆,當前主流ORM框架性能比較如下:
這裏寫圖片描述

Dao代碼生成

這裏寫圖片描述

“生成器”工程

  爲了在Android工程中使用greenDao,需要創建另一個“生成器”工程,它的任務是在你的工程域裏生成具體的代碼。
  這個“生成器”工程是一個正常的Java工程。“生成器”工程中需要在classpath中引入greenDAO-generator.jar和freemarker.jar兩個jar包。

生成的核心類文件

這裏寫圖片描述

DaoMaster:使用greenDao的入口,DaoMaster持有數據庫對象(SQLiteDatabase)併爲特定的模式管理Dao類。其中有創建和銷燬表的靜態方法。它的內部類OpenHelper 和DevOpenHelper是SQLiteOpenHelper 的實現,用來在SQLite數據庫中創建模式。
DaoSession:爲具體的模式管理所有可獲得的Dao對象,該對象可以通過其中的get方法獲得。DaoSession一些基礎的方法,比如對實體的插入,加載,更新,刷新和刪除等。DaoSession對象也保持了身份範圍的追蹤。
DAOs:數據訪問對象(DAOs)用來操作實體。對於每一個實體,greenDao生成一個Dao。它比DaoSession有更多操作數據庫的方法。
Entities:持久化對象。通常,實體被生成,實體對象相當於數據庫的一行。

構建實體

  使用greenDao的第一步就是在工程中創建代表應用程序中使用的數據的實體模型。這個模型用Java代碼,在“生成器”工程中定義。
  下圖描畫了元數據模型:
這裏寫圖片描述

  使用圖中的類來描述你所需要的具體的模型。

模式

  實體屬於一個模式。模式是你定義的第一個對象。

Schema schema = new Schema(1, "de.greenrobot.daoexample");

  模式的構造函數,需要兩個參數:

  • 模式版本號:
  • 默認的Java包名:這個默認包名在greenDao生成實體,DAOs和執行JUnit測試時使用。

如果想將DAO和用於測試的類生成在兩個分隔的包中,可以通過一下方法設置:

schema.setDefaultJavaPackageTest("de.greenrobot.daoexample.test");
schema.setDefaultJavaPackageDao("de.greenrobot.daoexample.dao");

  對實體模式還有兩個默認的標誌,它們可以被覆寫。這些標誌說明實體是否是激活的和是否保持章節字段可用。

schema2.enableKeepSectionsByDefault();
schema2.enableActiveEntitiesByDefault();
實體

  當有了模式對象,就可以向其中添加實體了。

Entity user = schema.addEntity("User");

  實體可以更改少數的幾項設置,更重要的是可以在其中添加屬性。

user.addIdProperty();
user.addStringProperty("name");
user.addStringProperty("password");
user.addIntProperty("yearOfBirth");

  每一個屬性對應生成對象中的一個字段,同時對應着數據庫中的一列。

屬性和主碼

  實體的addXXXProperty方法返回一個PropertyBuilder對象,它可以被用來配置屬性,例如用它來更改默認的列名。爲了訪問屬性對象(不是基本變量)需要在PropertyBuilder對象上使用getProperty()方法創建索引和關係。
  私有key的限制:現在,實體必須有一個long或Long的屬性作爲私有key。這是被Android和SQLite推薦的實踐(也可以使用唯一的字段作爲“key”屬性,只是不被推薦)。

默認

  greenDao儘量使其能工作在默認情況下。例如數據庫表名和列名是源於實體和屬性名的。默認的數據庫名是大寫並使用下劃線來分隔單詞。例如,一個屬性爲“creationDate”將變成一個名爲“CREATION_DATE”的數據庫列名。

關係

  數據庫表間有1:1,1:n或m:n的關係。
  在greenDao中,實體關係使用to-one或者to-many關係。如果你想在greenDao中做一個1:n關係的模型,則你要有一個to-one和一個to-many關係。注意to-one和to-many關係相互之間是沒有聯繫的,所以你需要兩個同時升級。

關係名稱和複合關係(Relation Names and multiple Relations)

  每一個關係都有名字,它被用來在生成的實體中保持這種關係。它的默認名字是目標實體的名字。這個名字可以使用setName()方法覆寫。記住如果還有一個實體對這個相同的實體有複合關係,則這個默認關係名字必須唯一。這種情況下,你必須明確定義對象名字。

構建To-One關係模型(Modelling To-One Relations)

  在greenDao生成器模型中,必須將一個屬性作爲外碼值,使用這個屬性,通過Entity.addToOne方法可以添加一個to-one關係。

// The variables "user" and "picture" are just regular entities
Property pictureIdProperty = user.addLongProperty("pictureId").getProperty();
user.addToOne(picture, pictureIdProperty);

  這個關係是,User實體中有一個Picture屬性(getPicture/setPicture),可以直接和該Picture對象進行交互。
  注意外碼屬性(”pictureId”)和實體對象屬性(”picture”)是綁定在一起的。如果改變了pictureId,則接下來調用getPictur()方法會得到更新ID後的新Picture實體。如果設置了新的Picture實體,則pictureId屬性也會更新。
  to-one關係的獲取方法第一次訪問目標實體時,需要現加載實體,所以比較緩慢,但隨後的訪問將直接返回之前加載的實體。
  greenDao也支持預加載to-one關係。它將用一條單獨的數據庫查詢解決一個實體與所有實體的to-one關係。目前,你可以使用生成的DAO的loadDeepqueryDeep去使用這些特徵。

關係名稱和複合關係(Relation Names and multiple Relations)

  現在擴展前面的例子,讓用戶也有一張縮略圖。因爲原圖和縮略圖都會關聯到關聯到一個相同的Picture實體,所以這會有一個命名衝突。因此,重命名第二個關係名稱爲“thumbnail”。

Property pictureIdProperty = user.addLongProperty("pictureId").getProperty();
Property thumbnailIdProperty = user.addLongProperty("thumbnailId").getProperty();
user.addToOne(picture, pictureIdProperty);
user.addToOne(picture, thumbnailIdProperty, "thumbnail");
構建To-Many關係模型(Modelling To-Many Relations)

  To-Many關係的模型創建同to-one關係的很像,只是外碼被放置在一張目的表中。下面讓我們看一個cusomer/order的例子。一個customer能放置多個order,這就是一個to-many關係。在數據庫中,通過增加一個customer ID列到order表中來創建1:N的關係。這樣,可以使用customer ID查詢一個customer的所有order。
  做To-Many關係模型,首先,你需要在目的實體中增加一個屬性去引用to-many關係的源實體。然後需要使用添加到目的實體中的屬性來向源實體增加一個to-many關係。
  假設我們有一個customer和一個order實體,我們想將orders和一個customer聯繫起來。下面的代碼向customer實體中添加了to-many關係。

Property customerId = order.addLongProperty("customerId").notNull().getProperty();
ToMany customerToOrders = customer.addToMany(order, customerId);
customerToOrders.setName("orders"); // Optional
customerToOrders.orderAsc(orderDate); // Optional

  這樣,可以使用Customer類的getOrders()方法去獲取所有的orders。

List orders = customer.getOrders();
解決和更新To-Many關係(Resolving and Updating To-Many Relations)

  第一次查詢時,To-Many關係是被解決緩慢的。這之後,相關的實體會被緩存在一個List列表中。隨後的訪問,不再查詢數據庫。
  注意更新to-many關係需要更多的工作。因爲to-many list列表已被緩存,當相關實體被添加到數據庫中時,它們不會被更新。下面的代碼說明了這個行爲:

List orders1 = customer.getOrders();
int size1 = orders1.size();

Order order = new Order();
order.setCustomerId(customer.getId());
daoSession.insert(order);

Listorders2 = customer.getOrders();
// size1 == orders2.size(); // NOT updated
// orders1 == orders2; // SAME list object

  因爲緩存,你應該向源實體(order)的to-many List列表中添加新的關聯實體。下面給出了怎樣插入新的實體:

  1. 獲取to-many Java List列表。
  2. 創建一個新的實體對象。
  3. 向目標實體中設置新的實體的外碼屬性。
  4. 插入新對象。
  5. 向to-many Java List列表中增加新的對象。

示例代碼:

List orders = customer.getOrders();
newOrder.setCustomerId(customer.getId());
daoSession.insert(newOrder);
orders.add(newOrder);

  注意getOrders()方法在插入之前調用以確保list列表被緩存。如果getOrders()方法在插入之後被調用,且orders之前沒有被緩存,則newOrder將出現在list列表中兩次。
  同樣的,你能刪除關聯實體:

List orders = customer.getOrders();
daoSession.delete(newOrder);
orders.remove(newOrder);

  有時,在關聯實體被添加或刪除後更新所有的to-many關係,是累贅的甚至是不可能的。爲了確保安全,greenDao提供了reset方法去清理緩存list列表。

customer.resetOrders();
List orders2 = customer.getOrders();
解決和更新To-Many關係(Bi-Directional 1:N Relations)

  有時你想要在雙向上導航1:N關係。在greenDao中,你不得不添加一個to-one和一個to-many關係來實現它。下面拓展了上面的示例,增加了雙向關係:

Entity customer = schema.addEntity("Customer");
customer.addIdProperty();
customer.addStringProperty("name").notNull();

Entity order = schema.addEntity("Order");
order.setTableName("ORDERS"); // "ORDER" is a reserved keyword
order.addIdProperty();
Property orderDate = order.addDateProperty("date").getProperty();
Property customerId = order.addLongProperty("customerId").notNull().getProperty();
order.addToOne(customer, customerId);

ToMany customerToOrders = customer.addToMany(order, customerId);
customerToOrders.setName("orders");
customerToOrders.orderAsc(orderDate);

  使用雙向關係,能夠像下面一樣,獲取customer和customer的所有orders:

List allOrdersOfCustomer = order.getCustomer().getOrders();
Many-to-Many關係 (n:m)

  數據庫中,可以使用一張連接表來構建n:m關係模型。當前greenDao不直接支持n:m關係,但可以構建一張連接表作爲分隔的實體。

構建Tree關係(Modelling Tree Relations)

  可以通過構建一個同時有to-one和to-many關係的實體來構建Tree關係。

Entity treeEntity = schema.addEntity("TreeEntity");
treeEntity.addIdProperty();
Property parentIdProperty = treeEntity.addLongProperty("parentId").getProperty();
treeEntity.addToOne(treeEntity, parentIdProperty).setName("parent");
treeEntity.addToMany(treeEntity, parentIdProperty).setName("children");

  獲取它的父和子的方法如下:

TreeEntity parent = child.getParent();
List grandChildren = child.getChildren();
繼承,接口和序列化

  實體可以從另一個不是實體的類繼承。超類使用setSuperclass(String)方法定義。注意,當前,讓另一個實體作爲超類是不可能的。

myEntity.setSuperclass("MyCommonBehavior");

  通常使用接口作爲實體屬性和行爲的基礎是很棒的。例如實體A和B共享一部分相同的屬性集,那麼這些屬性可以被定義在接口C中。

entityA.implementsInterface("C");
entityB.implementsInterface("C");

  可以設置一個實體實現序列化。

entityB.implementsSerializable();
JavaDoc和註解

  實體模型允許增加JavaDocs和Java註釋到實體和屬性。

myEntity.setJavaDoc("This is an hell of an entity.\nIt represents foos and bars.");
myEntity.setCodeBeforeClass("@Awesome");
myEntity.addIntProperty("counter")
  .codeBeforeField("@SerializedName(\"the-number-of-things\")")
  .javaDocGetterAndSetter("The total count");

  上面使用的方法在PropertyBuilder中提供,這些方法有:codeBeforeField, codeBeforeGetter, codeBeforeGetterAndSetter, codeBeforeSetter, javaDocField, javaDocGetter, javaDocGetterAndSetter, and javaDocSetter。

觸發代碼生成

  你需要的實體模式完成後,就可以觸發代碼生成進程。

DaoGenerator daoGenerator = new DaoGenerator();
daoGenerator.generateAll(schema, "../MyProject/src-gen");

  生成代碼時,需要一個模式對象和一個生成路徑,如果需要將用於測試的類生成到另外的路徑,可以使用第三個參數定義。

Keep章節

  實體類在每一次代碼生成時會被覆寫。爲了防止每次代碼生成時,覆寫掉自定義的代碼,greenDao提供了“keep”章節。處於該章節中的代碼不會被覆寫。

// KEEP INCLUDES - put your custom includes here
// KEEP INCLUDES END
...
// KEEP FIELDS - put your custom fields here
// KEEP FIELDS END
...
// KEEP METHODS - put your custom methods here
// KEEP METHODS END

  注意不要對上面生成的代碼進行編輯。

會話(Sessions)

  生成的DaoSession是greenDao的核心操作接口之一。DaoSession提供了訪問實體的基礎操作,DAOs則有更完全的的操作集。Sessions也管理着實體的標識範圍。

DaoMaster and DaoSession

  前面說過,獲取DaoSession需要創建一個DaoMaster:

daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
noteDao = daoSession.getNoteDao();

  注意數據庫連接屬於DaoMaster,所以多數的會話(Sessions)使用相同的數據庫連接。這樣新的會話能夠被更快速的創建。但每一個會話爲實體分配一個單獨的會話緩存。

標識範圍和會話緩存(Identity scope and session “cache”)

  如果你有兩個要返回相同數據庫對象的查詢,那麼會生成多少個Java對象,一個還是兩個?這依賴於標識範圍。在greenDao中默認的(這個行爲可以配置)是多次查詢返回同一個Java對象。例如,用ID 42在USER表中加載User對象,則每次查詢返回同一個Java對象。
  這種行爲是由於實體緩存的影響。如果一個實體仍在內存中(greenDao使用弱引用),則這個實體不會再用數據庫中的值重新構造。例如,如果你用同一個ID加載一個以前加過的實體,則greenDao不需要再查詢數據庫。所以它能很快的從會話緩存中返回對象。

數據庫操作

  對數據庫進行操作時,可以構建SQL語句進行操作,也可以使用greenDao的API進行操作。對於使用SQL語句進行操作,我們不在這裏講解,如果不熟悉可查閱相關資料進行學習。下面我們重點對greenDao的操作API進行講解。

插入(insert)

  • long insert(Bean entity)
    向數據庫表中插入Bean對象,返回插入表中的行ID。
  • void insertInTx(Iterable<Bean> entities)
    Tx後綴表示該操作使用數據庫事務,使用事務對於大數量的操作更高效。該方法表示,使用數據庫事務,向數據庫中插入一些對象。
  • void insertInTx(Bean... entities)
  • long insertOrReplace(Bean entity)
    數據庫中沒有待插入對象,則插入該對象,有則用該對象完全替換數據庫中數據。返回插入表中的行ID。
  • void insertOrReplaceInTx(Iterable<Bean> entities)
  • void insertOrReplaceInTx(Bean... entities)

刷新(refresh)

  • void refresh(Bean entity)
    從數據庫中加載一份新的數據到Bean緩存中,即對該Bean緩存緩存進行刷新。

更新(update)

  • void update(Bean entity)
    數據庫字段更新,數據庫中的字段完全更新爲entity中的數據,包括null。所以當有些字段不想更新時,具體邏輯需要進行控制。
  • void updateInTx(Iterable<Bean> entities)

刪除(delete)

  • void delete(Bean entity)
    從數據庫中刪除對象,該對象必須有唯一標識。
  • void deleteInTx(Iterable<Bean> entities)
  • void deleteInTx(Bean... entities)
  • void deleteByKey(long key)
    通過key從數據庫中刪除該條數據。
  • void deleteByKeyInTx(Iterable<Long> keys)
    -void deleteByKeyInTx(long... keys)
查詢刪除

  有些時候,我們需要對數據庫一些滿足刪除條件的數據執行批量刪除。這是可以使用查詢刪除的方法。爲了執行批量刪除,需要創建一個QueryBuilder並在其上調用buildDelete()方法,這回返回一個DeleteQuery對象。注意,目前這種批量刪除不會影響標識範圍內的實體,比如如果被刪除的實體之前通過他們的ID範圍並緩存過,則可以恢復它們。如果你使用這種方式引發了問題,則考慮清理標識範圍。

查詢(query)

  查詢支持懶加載(不使用緩存,每次查詢從數據庫讀取),這可以在操作大數據集時,節省內存,提升性能。

QueryBuilder

  QueryBuilder提供了greenDao查詢數據庫的API。下面給出一個它的基礎使用示例。
  查詢描述:獲取出生在1970年10月之後的,first name爲“joe”的用戶,並將結果按Last name降序排列。

QueryBuilder qb = userDao.queryBuilder();
qb.where(Properties.FirstName.eq("Joe"),
qb.or(Properties.YearOfBirth.gt(1970),
qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10)))).orderAsc(Properties.LastName);
List youngJoes = qb.list();
Limit和Offset

  有時,我們僅需要一個查詢結果的子集,例如盡查詢結果的前10項需要展示在UI。當要查詢的結果有大量數據時,限制查詢的數量是非常有用的,可以明顯的提升查詢效率和性能。QueryBuilder中定義了限制和偏移的方法。

  • limit(int):限制查詢返回結果的數量
  • offset(int):該方法需要和limit(int)方法結合使用,而不能單獨使用。它用來設置返回結果獲取時的偏移。它和limit(int)一起使用時,首先進行結果集的偏移,然後在返回限制的結果數量。
unique

  greenDao提供返回唯一的結果(0個或1個結果)或結果列表。如果你使用unique()方法希望獲取一個唯一的結果,則當存在查詢結果時,將返回給你一個單獨的結果,但當不存在查詢結果時,將返回一個null。如果你想避免返回一個null結果,則調用uniqueOrThrow()方法來保證返回的是不爲null的實體,但當不存在查詢結果時,將會拋出DaoException的異常。

list

  當需要一個查詢結果集時,可以使用list方法:

  • list():所有的實體被加載進內存。返回結果類型是ArrayList。
  • listLazy():實體按需求被加載進內存。一個元素一旦被訪問過一次,則其將被緩存起來以便之後直接使用。必須被關閉。
  • listLazyUncached():一個“虛擬的”實體列表。任何對該結果列表的訪問,都需要從數據庫中加載數據。必須被關閉。
  • listIterator():讓你可以遍歷按需加載出來的結果。數據不會被緩存。必須被關閉。

方法listLazy()listLazyUncached()listIterator()都使用了greenDao的LazyList類。爲了按需加載數據,它持有數據庫cursor的引用。這是爲什麼必須保證關閉lazy list和iterators的原因(通常在 try/finally塊中關閉)。如果所有的結果都被訪問或遍歷了,則listLazy()方法緩存的lazy list和listIterator()方法的lazy iterator會自動的關閉cursor。但如果你想過早地停止list的訪問,則你需要調動close()方法來主動關閉cursor。

多次執行查詢

  Query類代表了一個可以被多次執行的查詢。當你使用QueryBuilder中的方法獲取查詢結果時(比如list()方法),QueryBuilder在內部使用了Query類。如果你想多次使用一個相同的查詢,則你可以在QueryBuilder上調用build()方法來創建沒有執行的Query。
  複用一個Query比每次創建新的Query對象更有效率。如果再次查詢參數不需要改變,則你僅僅需要再次調用list/unique方法。如果查詢參數改變了,則你需要調用setParameter方法重新設置參數。目前,參數需要使用以0開始的索引尋址。這個索引基於你傳遞到QueryBuilder中參數的順序。
  下面的示例,先使用Query對象獲取了出生在1970年,first name爲Joe的用戶:

Query query = userDao.queryBuilder().where(
Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970))
.build();
List joesOf1970 = query.list();

  接下來,使用相同的Query對象,查詢出生在1977年,first name爲Marias的用戶:

query.setParameter(0, "Maria");
query.setParameter(1, 1977);
List mariasOf1977 = query.list();
多線程執行查詢

  如果在多線程中使用查詢,則需要在query上通過調用forCurrentThread()方法來獲取一個當前線程的Query實例。Query對象實例在創建查詢時被綁定到創建它的線程。這樣就可以安全的設置參數,而不會受其他線程的影響。如果其他線程嘗試在該query上設置參數或將該query綁定到其它線程,則會拋出異常。這樣,你就不需要自己進行同步。實際上應該避免加鎖,因爲在併發處理時使用相同的查詢對象,容易導致死鎖。
  爲了避免死鎖,greenDao提供了forCurrentThread()方法。這個方法返回一個當前線程的Query實例,在當前線程中使用它是絕對安全的。每次調用forCurrentThread()方法,參數都會被設置回query被創建時的初始參數。

原始SQL查詢

  某些情況下,QueryBuilder並不能滿足你的需求,則可以使用原始SQL查詢解決。有兩種執行SQL語句的方法。最常用的方式是使用QueryBuilder和WhereCondition.StringCondition。這種方式,你可以向query builder的where語句傳遞任意的SQL語句片段。下面示例展示了這種方式的使用方法:

Query query = userDao.queryBuilder().where(
new StringCondition("_ID IN " +
"(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)").build();

  另一種不使用QueryBuilder的方式是,在DAOs上使用queryRaw或queryRawCreate方法。你可以向它們傳入一個原始SQL語句,它會被添加到SELECT和實體字段後。用這種方式可以編寫任何WHERE和ORDER BY語句去查詢需要的實體集。實體表可以使用別名“T”來引用。使用示例如下:

Query query = userDao.queryRawCreate(
  ", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin");

  注意:可以使用生成的常量來表示表名和字段名。這是推薦的做法,可以避免編寫錯誤。在一個實體的DAO中,TABLENAME表示數據庫的表名,其內部類Properties則有所有屬性的常量。

分析故障

  如果沒有返回你期望的查詢結果,則可以打開QueryBuilder中的兩個關於打印SQL和執行參數的Log標識。

QueryBuilder.LOG_SQL = true;
QueryBuilder.LOG_VALUES = true;
連接查詢

  複雜的查詢通常需要獲取多個實體(表)的數據。使用SQL語言,可用方便地使用連接條件將兩個或更多表連接起來。
  讓我們考慮這樣一種情況,一個User實體,它和Address實體有1:n的關係,現在讓我們查詢住在“Sesame Street”的用戶。首先,我們必須使用User ID將User實體和Address實體連接,然後在Address實體上定義WHERE條件:

QueryBuilder<User> queryBuilder = userDao.queryBuilder();
queryBuilder.join(Properties.addressId, Address.class)
  .where(AddressDao.Properties.Street.eq("Sesame Street"));
List<User> users = queryBuilder.list();

  連接需要目標實體class和每個實體中的一個連接屬性作爲參數。在上面的例子中,沒有顯示地給出Address實體的連接屬性參數,這是因爲,Address實體中僅有一個連接屬性(address id)被定義,且該屬性爲主碼(PK),所以其被默認地使用。

QueryBuilder中的連接API
  • public <J> Join<T, J> join(Class<J> destinationEntityClass, Property destinationProperty)
    該方法中,主實體的主碼會被用來匹配給定的目標屬性(destinationEntityClass)。
  • public <J> Join<T, J> join(Property sourceProperty, Class<J> destinationEntityClass)
    該方法中,給出的源屬性(sourceProperty)是被用來匹配給出的目標實體(destinationEntityClass)的主碼。
  • public <J> Join<T, J> join(Property sourceProperty, Class<J> destinationEntityClass, Property destinationProperty)
    該方法中,給出的源屬性(sourceProperty)是被用來匹配給出的目標實體(destinationProperty)的目標屬性(destinationProperty)。
鏈式連接

  greenDao允許鏈式連接多個實體。即你可以使用一個連接和一個目標實體定義另一個連接。這種情況下,第一個連接的目標實體,變成了第二個連接的開始實體。
鏈式連接的API如下:
public <J> Join<T, J> join(Join<?, T> sourceJoin, Property sourceProperty, Class<J> destinationEntityClass, Property destinationProperty)
  下面給出一個三個實體連接的示例:City,Country和Continent。查詢在歐洲人口數超過100萬的所有城市:

QueryBuilder qb = cityDao.queryBuilder().where(Properties.Population.ge(1000000));
Join country = qb.join(Properties.CountryId, Country.class);
Join continent = qb.join(country, CountryDao.Properties.ContinentId, Continent.class, ContinentDao.Properties.Id);
continent.where(ContinentDao.Properties.Name.eq("Europe"));
List<City> bigEuropeanCities = qb.list();
自連接(可構成樹形結構)

  連接也可以用來連接多個相同實體。例如,假設我們有一個Person實體,其具有一個指向同類Person實體的fatherId屬性,現在我們想要找到所有祖父的名字是“Lincoln”的人。

QueryBuilder qb = personDao.queryBuilder();
Join father = qb.join(Person.class, Properties.FatherId);
Join grandfather = qb.join(father, Properties.FatherId, Person.class, Properties.Id);
grandfather.where(Properties.Name.eq("Lincoln"));
List<Person> lincolnDescendants = qb.list();

數據庫升級

  greenDao數據庫升級,首先需要提升“生成器”中的public Schema(int version, String defaultJavaPackage)方法中的數據庫版本字段。修改後,需要重新生成一遍代碼。接下來需要自定義一個繼承自DaoMaster.OpenHelper的類:

public class TestDevOpenHelper extends DaoMaster.OpenHelper {
    public TestDevOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
        super(context, name, factory);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //數據庫升級

    }
}

  自定義的TestDevOpenHelper類,在獲取DaoMaster時使用:

DaoMaster.OpenHelper helper = new TestDevOpenHelper(context, DATABASE_NAME, null);
DaoMaster daoMaster = new DaoMaster(helper.getWritableDatabase());

源碼地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章