谁有烟火的烟火百度云资源源 要可以看的那种不用登录网页 有字幕的谢谢大神

android - greenDao get auto-increment-ed ID - Stack Overflow
to customize your list.
Join the Stack Overflow Community
Stack Overflow is a community of 6.7 million programmers, just like you, helping each other.
J it only takes a minute:
Is it any way for me to get the next available ID for a table row (that would be automatically created when inserting a row in the table), so I would not be forced to insert that row at a given time, to get it?
To be more precise: I have an activity which contains a listview and each of those items are added using a second activity. When I finish adding the item details in the second activity, I pass that item through a parcelable object (I implemented Parcelable Interface to one of the holders class that DaoGenerator created). The id value of that object can not be null, to pass it with writeLong(id), and receive it with readLong() in my Parcelable methods, so I have to auto-generate the id value, by inserting the current item already in the database.
What I would like to do is: generate those IDs (without inserting the item in the database), pass that item to first activity, and when user decides to save all those items from the list, I would add all of them to database in a single transaction.
some sample code I have atm:
public class Question implements Parcelable {
private String questionC
// KEEP FIELDS - put your custom fields here
// KEEP FIELDS END
public Question() {
public Question(Long id) {
public Question(Long id,String questionContent) {
this.questionContent = questionC
public Long getId() {
public void setId(Long id) {
// KEEP METHODS - put your custom methods here
// begin Parcelable implementation
public int describeContents() {
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(id);
dest.writeString(questionContent);
public static final Parcelable.Creator&Question& CREATOR = new Parcelable.Creator&Question&() {
public Question createFromParcel(Parcel in) {
return new Question(in);
public Question[] newArray(int size) {
return new Question[size];
private Question(Parcel in) {
id = in.readLong();
questionContent = in.readString();
// end Parcelable implementation
// KEEP METHODS END
and this is how I create and send the item to list:
Question questionHolder = new Question(
etItemContent.getText().toString()
.trim(),);
Log.d(LOG_TAG, "question id = "
+ questionHolder.getId());
// inserting it here, would auto-generate the ID I required,
// but I would like to do that to all of the items in the first Activity (containing the list of all of the items)
// questionDao.insert(questionHolder);
Log.d(LOG_TAG, "question id = "
+ questionHolder.getId());
// add item to intent
Bundle b = new Bundle();
b.putParcelable(IMPORTANCE_TAG, questionHolder);
Intent intent = new Intent();
intent.putExtras(b);
setResult(RESULT_OK, intent);
QuestionItemActivity.this.finish();
I would not suggest this as it create too much tight coupling.
a couple options that comes to my mind:
If a field is nullable, I would suggest adding another flag to parcelable to denote if that field is null or not.
so when writing
if(id == null) {
out.writeByte((byte)0);
out.writeByte((byte)1);
out.writeLong(id);
and when reading
boolean hasId = in.readByte() == 1;
if(hasId) {
id = in.readLong();
Another option, since db ids start from 1, you can set id to 0 and handle this logically. so when you receive the object in your first activity, you can check the id and set to null if it is 0.
Yes there's a mean to do that, if you're using an ORM, this would be easy as !@#%.
All you have to do for example is:
Get the sequence name that generates the ID (there's always one even if you didn't create it manually).
Create an SQL query in your code for example :
session.createSQLQuery( "SELECT nextval( 'mySequenceName' )");
Then execute the query to retrieve the unique ID.
I hope this will help.
Your Answer
Sign up or
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Post as a guest
By posting your answer, you agree to the
Not the answer you're looking for?
Browse other questions tagged
rev .25036
Stack Overflow works best with JavaScript enabled[android]greendao 字符串主键-如何使用
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.
Greendao 常见问题解答中说"从 greenDAO 开始限制了对字符串的主键的支持."
我找不到任何地方,说: 这该怎么办。
我使用 Guid 作为我一个服务器应用程序中的主键,并且想要能够远程从 android 设备和上载回服务器生成新的数据。Android 设备上的数据库是在 sqlite 中,并使用 greenDAO 来生成 Pojo 和数据访问层。我正在使用 Guid 时,为避免主关键碰撞的数据上载到服务器。我作为字符串存储 Guid。
说应创建第二个域持有该字符串仍使用长主键青睐的 greendao,但这意味着我必须重新连接我的所有数据库关系时导入数据从服务器到 app,是一种痛苦的 greendao 网站上有一些更多的意见。将多宁愿只是继续使用字符串主键,如果这是可能的。
谁能告诉我这该怎么办?
下面是一些示例代码...
在我的发电机 (已经去除大多数为清楚起见字段):
private static void addTables(Schema schema)
Entity unit = addUnit(schema);
Entity forSale = addForSale(schema);
Property unitIntId = forSale.addLongProperty("unitIntId").getProperty();
forSale.addToOne(unit, unitIntId);
private static Entity addForSale(Schema schema)
Entity thisEntity = schema.addEntity("ForSale");
thisEntity.addIdProperty();
thisEntity.addStringProperty("forSaleId");
thisEntity.addFloatProperty("currentPriceSqFt");
thisEntity.addStringProperty("unitId");
return thisE
private static Entity addUnit(Schema schema)
Entity thisEntity = schema.addEntity("Unit");
thisEntity.addIdProperty();
thisEntity.addStringProperty("unitId");
thisEntity.addStringProperty("name");
return thisE
在我的 android 应用程序从服务器下载的所有数据。它有基于 GUID id 的关系我要重新为 int Id 我在像这样的生成器中创建这些连接:
//Add relations based on GUID relations
//ForSale:Units
for(ForSale forSale:Globals.getInstance().forSales)
if (forSale.getUnitId() != null && forSale.getUnit() == null)
for(Unit unit:Globals.getInstance().units)
if (forSale.getUnitId().equals(unit.getUnitId()))
forSale.setUnit(unit);
//only need the first one
所以我最终有两套的 Id 的链接一切,int 之一 greendao 和字符串 (guid) 之一,它获取上载到服务器时,将工作。必须是更容易的方法 !
解决方法 1:
试试这个:
private static void addTables(Schema schema) {
Entity unit = addUnit(schema);
Entity forSale = addForSale(schema);
Property unitId = forSale.addStringProperty("unitId").getProperty();
forSale.addToOne(unit, unitId);
private static Entity addForSale(Schema schema) {
Entity thisEntity = schema.addEntity("ForSale");
thisEntity.addStringProperty("forSaleId").primaryKey();
thisEntity.addFloatProperty("currentPriceSqFt");
return thisE
private static Entity addUnit(Schema schema) {
Entity thisEntity = schema.addEntity("Unit");
thisEntity.addStringProperty("unitId").primaryKey();
thisEntity.addStringProperty("name");
return thisE
如果刘洪舟映射将工作与字符串,但不知道如果不是你可以添加一些相关的对象保持各节中的方法。greenDao使用时遇到的坑 - 博客频道 - CSDN.NET
分类:android框架android问题
我的app中需要导入一个外部数据库,也就是一些死数据。
ID名不根据实体类命名来创建表
这是我外部数据库表的设计
这是greendao规定的ID命名
我要是不用greendao创建表,我就一直找不到这个坑了
Caused by: android.database.sqlite.SQLiteException: table t_book has no column named _id (code 1): , while compiling: INSERT INTO “t_book” (“_id”,”F_BOOK”) VALUES (?,?)
通过@Property()这个注解定义我外部数据库的字段名才能解决
@Entity(nameInDb = "t_book")
public class Book {
@Property(nameInDb = "id")
@Id(autoincrement = true)
private String f_
@Generated(hash = )
public Book(Long id, String f_book) {
this.f_book = f_
@Generated(hash = )
public Book() {
public Long getId() {
public void setId(Long id) {
public String getF_book() {
public void setF_book(String f_book) {
this.f_book = f_
排名:千里之外
(19)(1)(16)(1)(6)(1)(1)(1)(1)(4)(3)(6)(5)(1)(1)(1)greenDAO的使用
给出如下介绍:
greenDAO是一个对象关系映射(ORM)的框架,能够提供一个接口通过操作对象的方式去操作关系型数据库,它能够让你操作数据库时更简单、更方便。
在使用greenDAO的时候需要创建两个project,其中一个是java工程,它用来生成特定于您的项目的代码域(即生成了bean对象和操作数据库的dao)
核心的classes
DaoMaster:
DaoMaster保存了数据库对象和管理DAO类的classes,其提供了一些静态方法创建和删除表,内部类OpenHelper和DevOpenHelper 实现了SQLiteOpenHelper并创建数据库的框架。
DaoSession:
管理所有可用的DAO对象,可以通过getter方法获得。DaoSession还提供了一些通用的持久性方法比如插入、加载、更新,刷新和删除实体。
数据访问对象,每一个实体类都有对应的greenDAO对象。
Entities:
实体类对象
&h3 id=&核心greendao类初始化
helper = new DaoMaster.DevOpenHelper( this, &notes-db&, null);
db = helper.getWritableDatabase();
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
noteDao = daoSession.getNoteDao();
greenDAO 性能远远高于同类的 ORMLite,具体测试结果可见官网 greenDAO 支持 protocol buffer(protobuf) 协议数据的直接存储,如果你通过 protobuf 协议与服务器交互,将不需要任何的映射。 与 ORMLite 等使用注解方式的 ORM 框架不同,greenDAO 使用「Code generation」的方式,这也是其性能能大幅提升的原因。
1.新建Android project并在main目录下新建文件夹java-gen(存放自动生成bean和dao)
2.在build.gradle中配置
//buildTypes{}中配置
sourceSets {
java.srcDirs = ['src/main/java', 'src/main/java-gen']
//dependencies{}中配置
compile 'de.greenrobot:greendao:2.1.0'
3.新建java project——greenDAO_java
在build.gradle中添加
compile 'de.greenrobot:greendao-generator:2.1.0'
创建模式对象,并添加实体(表)
public class Generator {
public static void main(String[] args) throws Exception {
int version=1;
String defaultPackage=&test.greenDAO.bean&;
//创建模式对象,指定版本号和自动生成的bean对象的包名
Schema schema=new Schema(version,defaultPackage);
//指定自动生成的dao对象的包名,不指定则都DAO类生成在&test.greenDAO.bean&包中
schema.setDefaultPackageDao(&test.greenDAO.dao&);
//添加实体
addEntity(schema);
String outDir=&D:/adt-bundle-windows-x64/workspace/studio/frame/study_demo/testgreendao/src/main/java-gen&;
//调用DaoGenerator().generateAll方法自动生成代码到之前创建的java-gen目录下
new DaoGenerator().generateAll(schema,outDir);
private static void addEntity(Schema schema) {
//添加一个实体,则会自动生成实体Entity类
Entity entity = schema.addEntity(&Entity&);
//指定表名,如不指定,表名则为 Entity(即实体类名)
entity.setTableName(&student&);
//给实体类中添加属性(即给test表中添加字段)
entity.addIdProperty().autoincrement();//添加Id,自增长
entity.addStringProperty(&name&).notNull();//添加String类型的name,不能为空
entity.addIntProperty(&age&);//添加Int类型的age
entity.addDoubleProperty(&score&);//添加Double的score
4.运行java代码,自动在&project的java-gen目录下生成bean类和DAO类
5.新建MyApplication继承Application,并在Manifest文件中配置
public class MyApplication extends Application{
public DaoSession daoS
public SQLiteD
public DaoMaster.DevOpenH
public DaoMaster daoM
public void onCreate() {
super.onCreate();
setupDatabase();
private void setupDatabase() {
//创建数据库
// 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。
// 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。
helper = new DaoMaster.DevOpenHelper(this, &test&, null);
//得到数据库连接对象
db = helper.getWritableDatabase();
//得到数据库管理者
daoMaster =new DaoMaster(db);
//得到daoSession,可以执行增删改查操作
daoSession = daoMaster.newSession();
public DaoSession getDaoSession() {
return daoS
public SQLiteDatabase getDb() {
6.编写MainActivity中的代码,实现用greenDAO进行数据库的操作
初始化视图
tv_id = (TextView)findViewById(R.id.tv_id);
et_name = (EditText) findViewById(R.id.et_name);
et_age = (EditText) findViewById(R.id.et_age);
et_score = (EditText) findViewById(R.id.et_score);
btn_add = (Button) findViewById(R.id.btn_add);
btn_delete = (Button) findViewById(R.id.btn_delete);
btn_update = (Button) findViewById(R.id.btn_update);
btn_query = (Button) findViewById(R.id.btn_query);
lv_list = (ListView) findViewById(R.id.lv_list);
得到cursor对象
String orderBy = EntityDao.Properties.Id.columnName + & DESC&;//根据Id降序排序
//查询,得到cursor
cursor = getDb().query(getEntityDao().getTablename(), getEntityDao().getAllColumns(), null, null, null, null, orderBy);
btn_add.setOnClickListener(this);
btn_delete.setOnClickListener(this);
btn_update.setOnClickListener(this);
btn_query.setOnClickListener(this);
adapter = new MyAdapter(this, cursor);
lv_list.setAdapter(adapter);
lv_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView parent, View view, int position, long id_index) {
id = cursor.getLong(0);
tv_id.setText(&id: &+id);
et_name.setText(cursor.getString(1));
et_age.setText(cursor.getInt(2) + &&);
et_score.setText(cursor.getDouble(3) + &&);
自定义CursorAdapter
class MyAdapter extends CursorAdapter {
public MyAdapter(Context context, Cursor cursor) {
super(context, cursor);
public View newView(Context context, Cursor cursor, ViewGroup parent) {
ViewHolder holder = new ViewHolder();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.item_db, parent, false);
holder.tv_id = (TextView) view.findViewById(R.id.tv_id);
holder.tv_name = (TextView) view.findViewById(R.id.tv_name);
holder.tv_age = (TextView) view.findViewById(R.id.tv_age);
holder.tv_score = (TextView) view.findViewById(R.id.tv_score);
view.setTag(holder);
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder = (ViewHolder) view.getTag();
long id = cursor.getLong(0);
String name = cursor.getString(1);
int age = cursor.getInt(2);
double score = cursor.getDouble(3);
holder.tv_id.setText(id + &&);
holder.tv_name.setText(name);
holder.tv_age.setText(age + &&);
holder.tv_score.setText(score + &&);
static class ViewHolder {
TextView tv_
TextView tv_
TextView tv_
TextView tv_
数据库操作:增删改查的方法
private void addEntity() {
if (!TextUtils.isEmpty(name)) {
Entity entity = new Entity(null, name, age, score);
//面向对象添加表数据
getEntityDao().insert(entity);
cursor.requery();//刷新
Toast.makeText(MainActivity.this, &name不能为空&, Toast.LENGTH_SHORT).show();
* 根据id删除
* @param id
private void deleteEntity(long id) {
getEntityDao().deleteByKey(id);
cursor.requery();
private void updateList() {
Entity entity = new Entity(id, name, age, score);
getEntityDao().update(entity);
cursor.requery();
* 根据name查询
* @param name
private void query(String name) {
if (!TextUtils.isEmpty(this.name)) {
// Query 类代表了一个可以被重复执行的查询
Query query = getEntityDao().queryBuilder()
.where(EntityDao.Properties.Name.eq(this.name))
.orderAsc(EntityDao.Properties.Id)
// 查询结果以 List 返回
List count = query.list();
Toast.makeText(MainActivity.this, count.size() + &条数据被查到&, Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, &name不能为空&, Toast.LENGTH_SHORT).show();
demo演示:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1805次
排名:千里之外
转载:18篇
(2)(1)(9)(5)(4)(2)(1)(1)1084人阅读
Android开发(15)
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的loadDeep和queryDeep去使用这些特征。
关系名称和复合关系(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")
customerToOrders.orderAsc(orderDate)
  这样,可以使用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();
  因为缓存,你应该向源实体(order)的to-many List列表中添加新的关联实体。下面给出了怎样插入新的实体:
获取to-many Java List列表。
创建一个新的实体对象。
向目标实体中设置新的实体的外码属性。
插入新对象。
向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.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");
  生成代码时,需要一个模式对象和一个生成路径,如果需要将用于测试的类生成到另外的路径,可以使用第三个参数定义。
  实体类在每一次代码生成时会被覆写。为了防止每次代码生成时,覆写掉自定义的代码,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缓存缓存进行刷新。
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)一起使用时,首先进行结果集的偏移,然后在返回限制的结果数量。
  greenDao提供返回唯一的结果(0个或1个结果)或结果列表。如果你使用unique()方法希望获取一个唯一的结果,则当存在查询结果时,将返回给你一个单独的结果,但当不存在查询结果时,将返回一个null。如果你想避免返回一个null结果,则调用uniqueOrThrow()方法来保证返回的是不为null的实体,但当不存在查询结果时,将会抛出DaoException的异常。
  当需要一个查询结果集时,可以使用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))
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);
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());
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:10040次
排名:千里之外
原创:19篇
(2)(5)(3)(4)(5)}

我要回帖

更多关于 烟火百度云 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信