简介
这篇将介绍 ToMany。
如何实现关联
一对多的时候,只能将主表的 ID 保存在从表中。
一对一呢?
如果为了保持一致性,也将主表的 ID 保存在从表中,则查询语句是 select * from 从表 where 外键 = ? 。
如果采取相反的方式,则查询语句为 select * from 从表 where ID = ?。
效率上没什么区别,而 GreenDao 选择的是第二种。
如果不细究这些,GreenDao 还是有某种一致性,都有由主表发起建立联系,无论是 addToMany,还是 addToOne。
ListViewAdapter.java
package com.example.GreenDaoDemo4;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class ListViewAdapter extends BaseAdapter {
private List<Customer> data = new ArrayList<Customer>();
private LayoutInflater layoutInflater;
public ListViewAdapter(Activity activity) {
layoutInflater = activity.getLayoutInflater();
}
@Override
public int getCount() {
return data.size();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Customer customer = data.get(position);
String text = customer.getName();
List<Orders> ordersList = customer.getOrdersList();
for (Orders orders : ordersList) {
text += orders.getName();
}
TextView textView = (TextView) layoutInflater.inflate(R.layout.listview_item, parent, false);
textView.setText(text);
return textView;
}
public List<Customer> getData() {
return data;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
}
my_activity.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal">
<EditText android:id="@+id/etCustomerName"
android:layout_weight="1" android:layout_width="0dp"
android:layout_height="match_parent"
android:hint="customer"/>
<EditText android:id="@+id/etOrderName1"
android:layout_weight="1" android:layout_width="0dp"
android:layout_height="match_parent"
android:hint="order1"/>
<EditText android:id="@+id/etOrderName2"
android:layout_weight="1" android:layout_width="0dp"
android:layout_height="match_parent"
android:hint="order2"/>
<Button android:id="@+id/btnAdd"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="添加"/>
</LinearLayout>
<ListView android:id="@+id/lvNote"
android:layout_width="match_parent"
android:layout_height="0dp" android:layout_weight="1"/>
</LinearLayout>
MyActivity.java
public class MyActivity extends Activity implements View.OnClickListener {
private CustomerDao customerDao;
private OrdersDao ordersDao;
private ListViewAdapter listViewAdapter;
private EditText etCustomerName;
private EditText etOrderName1;
private EditText etOrderName2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
initDao();
initView();
refreshListView();
}
@Override
public void onClick(View v) {
onBtnAddClick();
}
private void initDao() {
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "person-db", null);
SQLiteDatabase db = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
DaoSession daoSession = daoMaster.newSession();
customerDao = daoSession.getCustomerDao();
ordersDao = daoSession.getOrdersDao();
}
private void initView() {
etCustomerName = (EditText) findViewById(R.id.etCustomerName);
etOrderName1 = (EditText) findViewById(R.id.etOrderName1);
etOrderName2 = (EditText) findViewById(R.id.etOrderName2);
findViewById(R.id.btnAdd).setOnClickListener(this);
ListView listView = (ListView) findViewById(R.id.lvNote);
listViewAdapter = new ListViewAdapter(this);
listView.setAdapter(listViewAdapter);
}
private void refreshListView() {
List<Customer> dataFromDb = customerDao.loadAll();
List<Customer> listViewData = listViewAdapter.getData();
listViewData.clear();
listViewData.addAll(dataFromDb);
listViewAdapter.notifyDataSetChanged();
}
private void onBtnAddClick() {
String customerName = etCustomerName.getText().toString();
String orderName1 = etOrderName1.getText().toString();
String orderName2 = etOrderName2.getText().toString();
Customer customer = new Customer(null, customerName);
customerDao.insert(customer);
Long customerId = customer.getId();
Orders orders1 = new Orders(null, orderName1, customerId);
ordersDao.insert(orders1);
Orders orders2 = new Orders(null, orderName2, customerId);
ordersDao.insert(orders2);
refreshListView();
}
}
缓存
public List<Orders> getOrdersList() {
if (ordersList == null) {
if (daoSession == null) {
throw new DaoException("Entity is detached from DAO context");
}
OrdersDao targetDao = daoSession.getOrdersDao();
List<Orders> ordersListNew = targetDao._queryCustomer_OrdersList(id);
synchronized (this) {
if(ordersList == null) {
ordersList = ordersListNew;
}
}
}
return ordersList;
}
上篇文章提到 GreenDao 默认使用的是懒加载,只有当调用 get 方法时,才会联动查询所关联的表。
当获得查询结果后,会将结果缓存起来,第二次调用 get 方法会返回之前的查询结果。
(这里做法是奇葩啊,每次确实都去查了一次,想干嘛? 第7行)
有时我们希望保持数据的一致性,有 2 种方法。
1. 手动同步,insert 之后对 list add,delete 后对 list remove。
2. 调用 reset 方法,将 list 重新赋值为 null,这样 get 方法就会获得数据库当前的数据了。
惯例,回顾一下那两个问题:
1. close 语句去哪了?
2. 数据库操作是另外开启线程的么?
附 MyDaoGenerator.java
public class MyDaoGenerator {
public static void main(String[] args) throws Exception {
Schema schema = new Schema(1, "com.example.GreenDao4");
Entity customerEntity = addCustomerEntity(schema);
addOrderEntity(schema, customerEntity);
new DaoGenerator().generateAll(schema, "D:\\");
}
private static Entity addCustomerEntity(Schema schema) {
Entity customerEntity = schema.addEntity("Customer");
customerEntity.addIdProperty();
customerEntity.addStringProperty("name").notNull();
return customerEntity;
}
private static Entity addOrderEntity(Schema schema, Entity customerEntity) {
Entity orderEntity = schema.addEntity("Orders"); // order 是关键字
orderEntity.addIdProperty();
orderEntity.addStringProperty("name").notNull();
Property customerIdProperty = orderEntity.addLongProperty("customerId").notNull().getProperty();
customerEntity.addToMany(orderEntity, customerIdProperty);
return orderEntity;
}
}