数据结构

家谱树数据结构

1、家庭成员数据库表存储结构,代码使用room存储数据

@Entity(tableName = "members")
data class FamilyMemberEntity(var name: String) {

    constructor() : this("")

    // 主键自增
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id")
    @SerializedName("id")
    var id: Long = 0

    // 父亲id
    @ColumnInfo(name = "fatherId")
    @SerializedName("fatherId")
    var fatherId: Long? = null

    // 配偶id
    @ColumnInfo(name = "spouseId")
    @SerializedName("spouseId")
    var spouseId: Long? = null

    // 性别
    @ColumnInfo(name = "sex")
    @SerializedName("sex")
    var sex: Int = 0

    // 手机号
    @ColumnInfo(name = "phone")
    @SerializedName("phone")
    var phone: String? = null // 手机号
    
    ...
    
}

其中id作为数据库主键自增。而fatherId和spouseId与其他成员建立联系,因为在一个家族之中一个成员的父亲和配偶都是唯一的(不考虑离异情况),而成员的母亲节点可以以父亲的配偶来获得(一夫一妻的情况),以此自上而下形成家族树关系。

2、家族树成员数据模型

/**
 * 家族树数据模型
 * */
data class FamilyMemberModel(var memberEntity: FamilyMemberEntity) {

    // 配偶
    var spouseEntity: FamilyMemberEntity? = null

    // 孩子
    var childModels: List<FamilyMemberModel>? = null

}

每个家族树成员包含三个成员:memberEntity、spouseEntity、childModels。其中memberEntity是当前成员的数据库信息,spouseEntity是当前成员配偶的信息,childModels是孩子的数据模型的集合。请注意childModels的类型是List<FamilyMemberModel>,也就是说childModels不仅包含孩子的基本信息,还包含孩子的配偶以及孩子的孩子信息。这是一种递归的表示方法,通过这种方法可以无限延伸下去。

3、数据库操作

@Dao
interface BaseDao<T> {

    @Insert
    fun insertItem(item: T) //插入单条数据

    @Insert
    fun insertItems(items: List<T>) //插入list数据

    @Delete
    fun deleteItem(item: T) //删除item

    @Update
    fun updateItem(item: T) //更新item

}

@Dao
interface FamilyMemberDao: BaseDao<FamilyMemberEntity> {

    /**
     * 根据id查询FamilyMemberEntity
     */
    @Query("SELECT * FROM members WHERE id = :id ")
    fun getMemberById(id: Long): FamilyMemberEntity

    /**
     * 根据id查询配偶信息
     */
    @Query("SELECT * FROM members WHERE spouseId = :spouseId ")
    fun getSpouseMemberById(spouseId: Long): FamilyMemberEntity

    /**
     * 根据id查询所有子FamilyMemberEntity集合
     */
    @Query("SELECT * FROM members WHERE fatherId = :id ")
    fun getChildMembers(id: Long): List<FamilyMemberEntity>

    /**
     * 查询全部结果
     */
    @Query("SELECT * FROM members")
    fun getAllMembers(): List<FamilyMemberEntity>

}

继承RoomDatabase

@Database(entities = {FamilyMemberEntity.class}, version = 1)
abstract public class FamilyDataBase extends RoomDatabase {

    public abstract FamilyMemberDao familyMemberDao();

}

这段代码使用java编写,之前使用kotlin,会报FamilyDataBase_impl未生成的错误,不知道啥原因,使用java就好了。

数据库操作工具类

class FamilyDataBaseHelper constructor(context: Context) {

    private val appDataBase = Room.databaseBuilder(context, FamilyDataBase::class.java,
        "family.db").build()!!

    companion object {
        @Volatile
        var INSTANCE: FamilyDataBaseHelper? = null

        fun getInstance(context: Context): FamilyDataBaseHelper {
            if (INSTANCE == null) {
                synchronized(FamilyDataBaseHelper::class) {
                    if (INSTANCE == null) {
                        INSTANCE = FamilyDataBaseHelper(context.applicationContext)
                    }
                }
            }
            return INSTANCE!!
        }
    }

    /**
     * 根据id获取Member
     */
    fun getFamilyMember(id: Long): FamilyMemberEntity{
        return appDataBase.familyMemberDao().getMemberById(id)
    }

    /**
     * 根据id获取配偶Member
     */
    fun getSpouseMember(id: Long): FamilyMemberEntity{
        return appDataBase.familyMemberDao().getSpouseMemberById(id)
    }

    /**
     * 根据id获取子Member
     */
    fun getChildMembers(id: Long): List<FamilyMemberEntity> {
        return appDataBase.familyMemberDao().getChildMembers(id)
    }

    /**
     * 更新FamilyMemberEntity;必须在非主线程中进行
     */
    fun updateMember(member: FamilyMemberEntity) {
        appDataBase.familyMemberDao().updateItem(member)
    }

    /**
     * 插入FamilyMemberEntity;必须在非主线程中进行
     */
    fun insertMember(member: FamilyMemberEntity) {
        appDataBase.familyMemberDao().insertItem(member)
    }
}

3、生成家族树数据模型

  1. 获取家族树根节点
var familyMember = FamilyDataBaseHelper.getInstance(this).getFamilyMember(1)

在非主线程调用,demo里面数据库只有一个家族树,所以我用第一条作为整个树的根节点。实际情况可以在表中添加一个根节点的标记字段还获取根节点。

2.通过跟节点生成家族树模型

if (familyMember != null) {
    var familyMemberModel = familyMember.generateMember(this)
}

这里调用generateMember方法来生成数据模型,我们来看一下这个方法的源码

/**
 * 将数据库数据转换成家族树成员模型
 * */
fun generateMember(context: Context) : FamilyMemberModel {

    var familyMemberModel = FamilyMemberModel(this)

    familyMemberModel.spouseEntity = FamilyDataBaseHelper.getInstance(context).getSpouseMember(id)

    familyMemberModel.childModels = getChildMembers(context)

    return familyMemberModel
}

private fun getChildMembers(context: Context): List<FamilyMemberModel> {
    var memberList = FamilyDataBaseHelper.getInstance(context).getChildMembers(id)
    var memberModelList = ArrayList<FamilyMemberModel>()
    for (member in memberList) {
        memberModelList.add(member.generateMember(context))
    }
    return memberModelList
}

其中当前节点的配偶通过查询数据库获得,获取孩子节点的getChildMembers方法里面会递归调用generateMember方法,从而延伸获取到整个家族树。

4、我们来插入一些测试数据,看一下最后显示的效果。

// 插入第一条数据,同时也是整个家族树的跟节点
var familyMember = FamilyMemberEntity("王根")
familyMember.imagePath = "111.jpg"
familyMember.phone = "18156094171"
familyMember.sex = 1
FamilyDataBaseHelper.getInstance(this).insertMember(familyMember)

familyMember = FamilyMemberEntity("王明")
familyMember.imagePath = "222.jpg"
familyMember.phone = "18156096666"
familyMember.fatherId = 1 // 父亲id为1,表示其父亲未第1条插入的数据,也就是上面的王根
familyMember.sex = 1
FamilyDataBaseHelper.getInstance(this).insertMember(familyMember)

familyMember = FamilyMemberEntity("王芸")
familyMember.imagePath = "222.jpg"
familyMember.phone = "18156096666"
familyMember.fatherId = 1 // 父亲id为1,表示其父亲未第1条插入的数据,也就是上面的王根
familyMember.sex = 0
FamilyDataBaseHelper.getInstance(this).insertMember(familyMember)

familyMember = FamilyMemberEntity("王恩")
familyMember.imagePath = "222.jpg"
familyMember.phone = "18156096666"
familyMember.fatherId = 2 // 父亲id为2,表示其父亲未第2条插入的数据,也就是上面的王明
familyMember.sex = 0
FamilyDataBaseHelper.getInstance(this).insertMember(familyMember)

对应的家族树如下:


familytre.jpg
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,448评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,648评论 3 406
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,816评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,288评论 1 304
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,294评论 6 401
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,739评论 1 316
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,076评论 3 431
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 41,071评论 0 280
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,632评论 1 327
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,637评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,755评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,344评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,069评论 3 341
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,487评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,646评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,342评论 3 384
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,813评论 2 367

推荐阅读更多精彩内容