史上最连忙的ORM方案

作者: 编程应用  发布:2019-09-06

世家好,在上一篇作品中,小编主要介绍了GreenDao3.0的最中心的用法,当然也是最常用的用法,假设您的项目里未有特意复杂的多表关联必要的话,笔者深信不疑这篇小说的知识点已经丰富使用了。但是,倘让你是二个求知欲非常强的人要么手上有要在地头创设复杂的数据库须求的话,小编信任认真读完本篇小说,你确定集会场全体收获。

目录

好了废话相当的少说,今日大家来读书下格林Dao的高档用法有哪些呢!阅读本篇小说前您供给对GreenDao有一定的摸底,倘使您对格林Dao掌握还远远不够的话,提出先去阅读史上最飞快的ORM方案——GreenDao3.0详解

session 缓存

  • session 缓存
  • 多表关联
  • 多表查询
  • ** 自定义参数类型**
  • 与数据库操作相关的AS插件

多表关联

纵然您有八个一律的查询语句去施行,猜猜看重返给你的指标是壹个依旧多少个?比方说像上面那样

多表查询

QueryBuilder<Project> projectQueryBuilder = projectDao .queryBuilder() .where(ProjectDao.Properties.UserName.eq);Query<Project> query = projectQueryBuilder.build();Project project1=query.unique();QueryBuilder<Project> projectQueryBuilder1 = projectDao .queryBuilder() .where(ProjectDao.Properties.UserName.eq);Query<Project> query2 = projectQueryBuilder1.build();Project project2=query.unique();

自定义参数类型

答案是project1==project2何况project2查询出来的进程要比project1查询出来的速度快比较多倍;这是因为在同贰个session中一经一个entities已经被session记录那么下三回重复操作该实体时,greenDao会先从内部存款和储蓄器中寻觅,借使内部存款和储蓄器中未有再去数据库中探寻。那样一边就大幅度的增高greenDao的询问作用,另一方面也是索要特别注意的是当entities更新过 greenDao还是会从内部存储器中抽取旧值,所以倘诺entities更新过,要求去调用daoseesion.clear()方法清除缓存后才能查到新型值,否则查询到的将照旧保存在内部存储器中的值。上面介绍下清除缓存有两种方式

与数据库操作相关的AS插件

  • 免除所负有的缓存

session 缓存

要是您有八个一律的查询语句去施行,猜猜看再次回到给您的对象是贰个依然多少个?比方说像上面那样

daoSession.clear();

QueryBuilder<Project> projectQueryBuilder = projectDao
.queryBuilder()
.where(ProjectDao.Properties.UserName.eq("123456"));
Query<Project> query = projectQueryBuilder.build();
Project project1=query.unique();
QueryBuilder<Project> projectQueryBuilder1 = projectDao
.queryBuilder()
.where(ProjectDao.Properties.UserName.eq("123456"));
Query<Project> query2 = projectQueryBuilder1.build();
Project project2=query.unique();

  • 解除钦点Dao类的缓存

答案是project1==project2何况project2询问出来的速度要比project1查询出来的进度快比很多倍;

那是因为在同贰个session中只要一个entities已经被session记录那么下贰次重复操作该实体时,greenDao会先从内存中找找,借使内部存款和储蓄器中未有再去数据库中检索。那样一方面就小幅的滋长greenDao的询问作用,另一方面也是亟需非常注意的是当entities更新过 greenDao还是会从内存中抽取旧值,所以若果entities更新过,供给去调用daoseesion.clear()方法清除缓存后技艺查到最新值,不然查询到的将还是保存在内部存款和储蓄器中的值。

projectDao = daoSession.getNoteDao();projectDao.detachAll();

1. 1:1关联当咱们在采取sqlite数据库来完结表的1:1涉嫌时,平时大家会在主表中定义三个外键去关联副表,当要询问相应的数量时,首先大家要驾驭查询数据的外键,然后必要用外键去副表中询问所急需的多少。举个例子上边那样

上边介绍下清除缓存有两种方式

 public class Customer { private Long id; } public class Order { private Long id; private Date date; private long customerId; }

扫除所负有的缓存

Customer表通过id与Order表关联,查询Order的Customer时亟需先清楚Order中的customerId然后依照id=customerId值再去数据库中询问该id所对应的Customer对象。不过在greenDao中一个讲解就能够化解,只须要选用@ToOne注释来定义贰个关联对象就能够。

daoSession.clear();

@ToOne 定义了贰个entities与另一个entities的1:1对应涉及。通过joinProperty参数来定义贰个外键上边是代码示例

破除内定Dao类的缓存

public class Order { @Id private Long id; private long customerId; @ToOne(joinProperty = "customerId") private Customer customer;}@Entitypublic class Customer { @Id private Long id;}

projectDao = daoSession.getNoteDao();projectDao.detachAll();

这般只要取得Order对象就能够通过getCustomer()方法获得Order所对应的Customer了,这样是否异常高效,很方便。其实getCustomer方法也很简短,就是在底层支持大家封装好了询问语句而已,别的getCustomer获取的靶子也是懒查询机制,唯有真正使用getCustomer方法查询到的靶羊时greenDao才会奉行查询操作。要是你想立马奉行查询操作能够调用DAO类的loadDeep()与queryDeep()方法。

多表关联

2. 1:N 关联在1对1提到中种种顾客只可以与四个订单对应,可是现实生活中必定不只是这样,也会冒出一个主顾下多少个订单的动静。即使现身这种要求的话,依照原生Sqlite的思绪一致是经过外键关联就能够,只是这一遍询问的对象会有那些个,然则利用greenDao的1:1关乎格局胸有成竹极度。然则别忧虑greenDao还给我们计划了@ToMany注释。

1. 1:1关联

@ToMany 定义了三个entities与另一个entities(这些符号为对象实体)的三个指标的涉嫌关系:@汤姆any有须臾间三种办法来定义1:N的照耀关系。

当大家在动用sqlite数据库来促成表的1:1关系时,常常大家会在主表中定义一个外键去关联副表,当要查询相应的多寡时,首先大家要了然查询数据的外键,然后须求用外键去副表中查询所须求的数码。举例上面那样

  • referencedJoinProperty 在指标实体中大家供给定义三个与源实体关联起来的外键,即Order中的customerId,然后须要在源实体里大家必要将customerId作为referencedJoinProperty的习性。聊起来很别扭,其实代码很简短;

public class Customer {
private Long id;
}
public class Order {
private Long id;
private Date date;
private long customerId;
}

Customer表通过id与Order表关联,查询Order的Customer时亟需先精通Order中的customerId然后基于id=customerId值再去数据库中询问该id所对应的Customer对象。可是在greenDao中贰个讲解就能够消除,只供给运用@ToOne注释来定义三个提到对象就能够。

 @Entity public class Customer { @Id private Long id; @ToMany(referencedJoinProperty = "customerId") @OrderBy("date ASC") private List<Order> orders; } @Entity public class Order { @Id private Long id; private Date date; private long customerId; }

@ToOne 定义了一个entities与另一个entities的1:1对应涉及。通过joinProperty参数来定义三个外键上面是代码示例

是或不是很简短通过referencedJoinProperty来标记下俩个实体之间的外键就可以

public class Order {
@Id
private Long id;

  • joinProperties以此参数是referencedJoinProperty 参数的进级版。在referencedJoinProperty参数中我们开采俩个实体关联的外键是CustomerId与id,但是只要大家的要求是外键无法透过id来定义,需求用自个儿自定义属性来定义,第一种办法就无法用了,而joinProperties即便为了缓慢解决那些须要的。

private long customerId;

@ToOne(joinProperty = "customerId")
private Customer customer;
}

 @Entity public class Customer { @Id private Long id; @Unique private String tag; @ToMany(joinProperties = { @JoinProperty(name = "tag", referencedName = "customerTag") }) @OrderBy("date ASC") private List<Site> orders; } @Entity public class Order { @Id private Long id; private Date date; @NotNull private String customerTag; }

@Entity
public class Customer {
@Id
private Long id;
}

实在假使把

如此那般假使得到Order对象就能够通过getCustomer()方法得到Order所对应的Customer了,那样是或不是相当高效,很便利。其实getCustomer方法也相当粗略,即是在底层支持大家封装好了查询语句而已,其余getCustomer获取的对象也是懒查询机制,唯有真正使用getCustomer方法查询到的对象时greenDao才会实践查询操作。若是你想立时施行查询操作能够调用DAO类的loadDeep()与queryDeep()方法。

 @ToMany(joinProperties = { @JoinProperty(name = "id", referencedName = "customerId") })

2. 1:N 关联

那样的话就和率先种艺术完结原理是同样的了。

在1对1涉及中每一种开支者只好与贰个订单对应,但是现实生活中无庸置疑不只是那般,也会产出八个客户下两个订单的情状。借使出现这种须要的话,依据原生Sqlite的思绪同样是通过外键关联就可以,只是那一回询问的目的会有为数十分的多个,可是选取greenDao的1:1提到方式明显十二分。可是别忧郁greenDao还给大家计划了@ToMany注释。

  • @JoinEntity 定义了N:M的映照关系。

**@ToMany **概念了叁个entities(这一个符号为源实体)与另一个entities(那几个标志为对象实体)的多少个目的的涉嫌关系:@汤姆any有弹指间三种方法来定义1:N的映照关系。

referencedJoinProperty 在对象实体中我们须要定义叁个与源实体关联起来的外键,即Order中的customerId,然后须求在源实体里我们需求将customerId作为referencedJoinProperty的性质。聊到来很隐晦,其实代码很轻松;

 @Entity public class Product { @Id private Long id; @ToMany @JoinEntity( entity = JoinProductsWithOrders.class, sourceProperty = "productId", targetProperty = "orderId" ) private List<Order> ordersWithThisProduct; } @Entity public class JoinProductsWithOrders { @Id private Long id; private Long productId; private Long orderId; } @Entity public class Order { @Id private Long id; }

@Entity
public class Customer {
@Id private Long id;

3. 关联表的翻新与解析事关的询问也是懒加运载飞机制,况兼查询的结果会保留在缓存中下次询问的时候假若缓存有会一向从缓存中获得结果。

  @ToMany(referencedJoinProperty = "customerId")
  @OrderBy("date ASC")
  private List<Order> orders;

未有差距于关联表更新时因为有缓存机制的留存你需求将改换的表手动的通过add()方法来更新关联表中的对象或许直接铲除缓存。

}

// 获取当前顾客的订单列表List<Order> orders1 = customer.getOrders();// 插入一个新订单Order order = new Order();order.setCustomerId(customer.getId;daoSession.insert;// 再一次获取顾客的订单List<Order> orders2 = customer.getOrders();// 因为缓存列表没有更新所以订单1与订单2的大小相等assert(orders1.size() == orders2.size);// 也是相同的对象assert(orders1.equals;//调用该方法后,才能更新缓存列表orders1.add;//删除时也许要手动将缓存列表里面的数据删除List orders = customer.getOrders();// 从数据库中移除daoSession.delete(someOrder);// 手动从缓存列表移除orders.remove(someOrder);//如果数据库更新后不想手动添加数据可以使用resetXX()方法来清除缓存customer.resetOrders();List orders = customer.getOrders();

@Entity
public class Order {
@Id private Long id;
private Date date;
private long customerId;
}

些微时候我们的表未有运用ToOneToMany创设关系关系,但是大家又想一步到位。那时大家得以选用greenDao的多表查询作用来救助大家减弱不供给的代码。1. 关系单个表

是还是不是很简短通过referencedJoinProperty来注解下俩个实体之间的外键就可以

//查询地址是住在迪拜大楼的用户QueryBuilder<User> queryBuilder = userDao.queryBuilder();queryBuilder.join(Address.class, AddressDao.Properties.userId) .where(AddressDao.Properties.Street.eq;List<User> users = queryBuilder.list();

joinProperties以此参数是referencedJoinProperty参数的进级版。在referencedJoinProperty参数中大家开掘俩个实体关联的外键是CustomerId与id,可是如果大家的须求是外键不可能由此id来定义,必要用本人自定义属性来定义,第一种办法就没有办法用了,而joinProperties不怕为了解决那一个要求的。

经过queryBuilder.join()方法就能够成功,其用法也很简短第多少个参数是事关的类,第叁个是关联类中的关联属性。

@Entity
public class Customer {
@Id private Long id;
@Unique private String tag;

2.涉嫌七个表

  @ToMany(joinProperties = {
          @JoinProperty(name = "tag", referencedName = "customerTag")
  })
  @OrderBy("date ASC")
  private List<Site> orders;
//查询在欧洲人口超过100000的城市QueryBuilder qb = cityDao.queryBuilder().where(Properties.Population.ge;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);List<City> bigEuropeanCities = qb.list();

}

经过queryBuilder.join()链式调用来兑现多表查询注意:多表查询的前提是大家已经定义好了外键来关联表与表之间的关系。

@Entity
public class Order {
@Id private Long id;
private Date date;
@NotNull private String customerTag;
}

  1. 暗中同意类型参数 :greenDao私下认可协理的体系参数如下

骨子里只要把

@ToMany(joinProperties = {
@JoinProperty(name = "id", referencedName = "customerId")
})

boolean, Booleanint, Integershort, Shortlong, Longfloat, Floatdouble, Doublebyte, Bytebyte[]StringDate

那样的话就和率先种形式实现原理是一律的了。

  1. 自定义类型参数: 即使greenDao的暗中认可参数类型满意不断你的须要,举例你想定义三个颜色属性,那么你能够动用数据库扶助的原生数据类型通过PropertyConverter类转换到你想要的水彩属性。

@JoinEntity 定义了N:M的照射关系。

  • 先是你需求给自定义类型参数增加 @Convert批注并丰盛对应参数converter:参数调换类,columnType:在数据库中对应的项目
  • 实现PropertyConverter类上边是用经过使用数据库匡助的Integer类型来调换来数据库不协理的枚举类型

@Entity
public class Product {
@Id private Long id;

  @ToMany
  @JoinEntity(
          entity = JoinProductsWithOrders.class,
          sourceProperty = "productId",
          targetProperty = "orderId"
  )
  private List<Order> ordersWithThisProduct;
@Entitypublic class User { @Id private Long id; @Convert(converter = RoleConverter.class, columnType = Integer.class) private Role role; public enum Role { DEFAULT, AUTHOR, ADMIN; final int id; Role { this.id = id; } } public static class RoleConverter implements PropertyConverter<Role, Integer> { //将Integer值转换成Role值 @Override public Role convertToEntityProperty(Integer databaseValue) { if (databaseValue == null) { return null; } for (Role role : Role.values { if (role.id == databaseValue) { return role; } } return Role.DEFAULT; } //将Role值转换成Integer值 @Override public Integer convertToDatabaseValue(Role entityProperty) { return entityProperty == null ? null : entityProperty.id; } }}

}

  • 异常的快清除数据库本地数据。ADB IDEA
  • 调理工具同偶尔候能够长足查看数据表结会谈数码。 Stetho

@Entity
public class JoinProductsWithOrders {
@Id private Long id;
private Long productId;
private Long orderId;
}

感兴趣的校友能够寻觅下那俩个插件真的很好用。

@Entity
public class Order {
@Id private Long id;
}

上一期有同学提问greenDao的二十八线程同步机制,在那边本身轻易表明下:greenDao十二线程同步能够通过forCurrentThread()来落实的,具体原理很轻松大家看下源码就明白了

3. 关联表的换代与深入分析

 //获取当前线程id long threadId = Thread.currentThread; //加锁 synchronized (queriesForThreads) { //queryRef是一个Map集合 WeakReference<Q> queryRef = queriesForThreads.get; Q query = queryRef != null ? queryRef.get() : null; if (query == null) { gc(); query = createQuery(); //保存query queriesForThreads.put(threadId, new WeakReference<Q>; } else { System.arraycopy(initialValues, 0, query.parameters, 0, initialValues.length); } return query; }

涉及的询问也是懒加运载飞机制,何况查询的结果会保留在缓存中下一次查询的时候假如缓存有会一直从缓存中获取结果。

那是源码的中央部分,从上边我们得以见见greenDao是因而将线程id与query对象存款和储蓄在Map集结中国建工业总会公司立1:N的映射关系,区别线程只会收取属于自个儿的query而不会调用别的线程的query。

同等关联表更新时因为有缓存机制的存在你要求将转移的表手动的通过add()方法来更新关联表中的对象恐怕直接铲除缓存。

对了,那几个源码地址作者会放在简书的评价里,假如有亟待的同室能够来本人的简书中取得。假设您感觉本篇文章对你有扶持的话,点个爱护照旧关怀呢!下一期笔者将介绍有关android动画的相关文化,尽管对动画片还不太驾驭的同班,赶紧关怀笔者吧!

// 获取当前花费者的订单列表
List<Order> orders1 = customer.getOrders();

// 插入叁个新订单
Order order = new Order();
order.setCustomerId(customer.getId());
daoSession.insert(order);

// 再叁回得到花费者的订单
List<Order> orders2 = customer.getOrders();

// 因为缓存列表未有更新所以订单1与订单2的深浅相等
assert(orders1.size() == orders2.size);
// 也是同一的靶子
assert(orders1.equals(orders2));

//调用该措施后,能力创新缓存列表
orders1.add(newOrder);

//删除时恐怕要手动将缓存列表里面包车型地铁数码删除
List orders = customer.getOrders();
// 从数据库中移除
daoSession.delete(someOrder);
// 手动从缓存列表移除
orders.remove(someOrder);

//假设数据库更新后不想手动增添数据足以动用resetXX()方法来祛除缓存

customer.resetOrders();
List orders = customer.getOrders();

多表查询

某些时候大家的表未有动用ToOneToMany树立关系关系,可是大家又想一步到位。那时大家得以行使greenDao的多表查询效率来协助我们减少不须要的代码。

1. 关系单个表

//查询地址是住在东京大楼的客商
QueryBuilder<User> queryBuilder = userDao.queryBuilder();
queryBuilder.join(Address.class, AddressDao.Properties.userId)
.where(AddressDao.Properties.Street.eq("巴黎大楼"));
List<User> users = queryBuilder.list();

经过queryBuilder.join()方法就可以到位,其用法也很简单第一个参数是涉嫌的类,第四个是关联类中的关联属性。

2.关乎多个表

//查询在北美洲总人口超越一千00的都市
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();

透过queryBuilder.join()链式调用来达成多表查询

只顾:多表查询的前提是我们曾经定义好了外键来关联表与表之间的关系。

自定义参数类型

1.暗中认可类型参数 :greenDao私下认可帮衬的门类参数如下

boolean, Boolean
int, Integer
short, Short
long, Long
float, Float
double, Double
byte, Byte
byte[]
String
Date

2.自定义类型参数: 如若greenDao的暗许参数类型满足不断你的急需,举个例子您想定义二个颜料属性,那么您能够行使数据库帮衬的原生数据类型通过PropertyConverter类调换到你想要的颜料属性。

第一你需求给自定义类型参数增多 @Convert评释并累加对应参数
converter:参数转变类,columnType:在数据库中对应的花色

实现PropertyConverter

上边是用经过行使数据库帮助的Integer类型来转换来数据库不补助的枚举类型

@Entity
public class User {
@Id
private Long id;

@Convert(converter = RoleConverter.class, columnType = Integer.class)
private Role role;

public enum Role {
DEFAULT(0), AUTHOR(1), ADMIN(2);
final int id;

Role(int id) {
this.id = id;
}
}

public static class RoleConverter implements PropertyConverter<Role, Integer> {
//将Integer值转变到Role值
@Override
public Role convertToEntityProperty(Integer databaseValue) {
if (databaseValue == null) {
return null;
}
for (Role role : Role.values()) {
if (role.id == databaseValue) {
return role;
}
}
return Role.DEFAULT;
}

//将Role值转变来Integer值
@Override
public Integer convertToDatabaseValue(Role entityProperty) {
return entityProperty == null ? null : entityProperty.id;
}
}
}

与数据库相关的AS插件

高速清除数据库本地数据--ADB IDEA

调整工具相同的时候能够高速查看数据表结交涉多少--Stetho

感兴趣的同室能够搜寻下这俩个插件真的很好用。

后记

上期有同学有同学咨询greenDao的八线程同步机制,在这里本人简单表达下:
greenDao八线程同步能够由此forCurrentThread()来落到实处的,具体原理非常粗略我们看下源码就明白了

  //获取当前线程id
   long threadId = Thread.currentThread().getId();
  //加锁
    synchronized (queriesForThreads) {
        //queryRef是一个Map集合
        WeakReference<Q> queryRef = queriesForThreads.get(threadId);
        Q query = queryRef != null ? queryRef.get() : null;
        if (query == null) {
            gc();
            query = createQuery();
            //保存query
            queriesForThreads.put(threadId, new WeakReference<Q>(query));
        } else {
            System.arraycopy(initialValues, 0, query.parameters, 0, initialValues.length);
        }
        return query;
    }

这是源码的中央部分,从地点大家能够看来greenDao是透过将线程id与query对象存款和储蓄在Map集结中国建工业总集结团立1:N的绚烂关系,区别线程只会收取属于自个儿的query而不会调用其余线程的query。

本文由今晚开什么码发布于编程应用,转载请注明出处:史上最连忙的ORM方案

关键词:

上一篇:没有了
下一篇:没有了