XML万能数据库C#版

来源:互联网 发布:java public 方法 编辑:程序博客网 时间:2024/06/05 08:47

使用unity开发存取本地数据一般用xml,来实现跨平台的数据存取。为什么不用sqlite我就不解释了,谁用谁知道。

好进入正题,如果你了解hibernate,应该知道他是针对model层数据持久化操作的利器。什么意思呢,也就是说任意对象的增删改查它都帮你做了,你需要做的就是配置一下即可。使用时直接调用提供的接口。JavaC#都有这样的利器。

但是hibernate一般用于web应用,需要处理大量的实体类,虽然用unity开发的游戏也需要对一些类进行持久化操作,但是用hibernate还是太专业了,大材小用不说,好像并不怎么适用。配置什么的应该很烦。但是还想一劳永逸,只写一个操作适用所有对象的增删改查怎么办?自己动手丰衣足食。

首先要知道hibernate是怎么实现的类的自动拆装的,反射。OK,接下来就简单了,知道了方案,接下来就是具体的实现了。楼主看了下C#的反射,没想到实在是太好用了!

好,整理一下基本思路,类的名称作为表名,类的成员变量作为列名,成员变量的值作为值,进行存取。等等,xml又不是sql,这表,列,值代表什么意思呢?如果你学过xml的话,应该知道根,元素。(小白先去学基础知识吧),所以我们存取对象就是把这个对象的名称作为根,字段作为子根进行存取。

以上是xml实现基础,如何做到万能,还需要结合反射,通过反射可以获取的信息:类的名称,类的成员变量,值,等等。所以,存取对象的时候,先将这个类进行解析,获取类名,他的成员变量,以及值,存起来,然后插入的时候,以类名为根,成员变量作为元素,值作为元素的值插入。因为xml存的是字符,所以类型在存的时候都转成字符串。取的时候再将字符串转成相应的类型,封装成对象即可。

不知道听不听的懂,代码是最通俗的,好,进入正题。

首先,你要处理的是泛型对象,这样在操作的时候不需要强转。先写个接口声明一下。插入的时候直接传对象,查找的时候也传对象(默认按ID查找,需要在代码中对ID赋值),更新有两种,一是更新指定的列,二是更新对象的所有列。删除直接传对象。

using System.Collections.Generic;using System;public interface DataBase {    void Insert<T>(T t);    T Select<T>(T t);    List<T> SelectAll<T>(T t);    void Update<T>(T t,string key);    void Update<T>(T t);    void Delete<T>(T t);    void CreateData(string path);}
然后,写个静态的类,使用这个万能xml,代码也很简单,如果有疑惑,我稍后解答,例如为什么写成静态的?

using System.Collections.Generic;using System;using UnityEngine;public class MyDataBase{     private static DataBase database;    public static string RESDATAPATH = Application.streamingAssetsPath;    //源数据目录    private static string DATAPATH = Application.dataPath;    //数据目录    static MyDataBase() {          #if UNITY_ANDROID        DATAPATH = Application.persistentDataPath; #endif        database = new XmlDataBase(DATAPATH);    }     public static void Insert<T>(T t)    {        database.Insert(t);         }    public static T Select<T>(T t)    {        return database.Select(t);    }    public static List<T> SelectAll<T>(T t)    {        return database.SelectAll<T>(t);    }    public static void Update<T>(T t, string key)    {        database.Update(t, key);    }    public static void Update<T>(T t)    {        database.Update(t);    }    public static void Delete<T>(T t)    {        database.Delete(t);    }     }

好,下面就是xml的存取操作了,不怎么难,关键是一些方法的运用。

using UnityEngine;using System.Xml;using System.Collections.Generic;using System.IO;using System;public class XmlDataBase : DataBase{    private string path = "/DataBase/GameData.xml";    private  string Myroot = "MyData";    private  XmlDocument xmlDoc = new XmlDocument();    public static string ObjectID="ID";    public static string PATH;    private void ReadFile(string path) {        PATH = path + this.path;        if (!File.Exists(PATH))//如果指定的路径不存在        {            if (!File.Exists(MyDataBase.RESDATAPATH + this.path))//如果不存在源文件            {                Directory.CreateDirectory(MyDataBase.RESDATAPATH + "/DataBase");                File.CreateText(PATH);                CreateData((MyDataBase.RESDATAPATH + this.path));                Application.Quit();            }            else {                Directory.CreateDirectory(path + "/DataBase");                File.CreateText(PATH);                File.Copy(MyDataBase.RESDATAPATH + this.path, PATH);                File.Delete(MyDataBase.RESDATAPATH + this.path);            }        }        else        {            xmlDoc.Load(PATH);                    }    }    public XmlDataBase()    {        //这是一个XML数据库,基于XML的对象的存取,改查操作。        //注意,数据对象的ID需要以字母开头,且不能有特殊字符。        //TextAsset textAsset = (TextAsset)Resources.Load(file, typeof(TextAsset));        ReadFile(path);//读取默认路径    }    public XmlDataBase(string path)    {        ReadFile(path);//指定读取默认路径    }    public void CreateData(string path)    {                XmlDocument xmlDoc = new XmlDocument();        XmlDeclaration xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);        XmlNode root = xmlDoc.CreateElement(Myroot);        xmlDoc.AppendChild(xmlDeclaration);        xmlDoc.AppendChild(root);        xmlDoc.Save(path);    }    public void Insert<T>(T obj)    {        //插入一个对象        //对象有字段,属性值        //利用数据的特点,即名称不同,优化查询速度,具体的做法为,将属性值作为子根操作。        ObjectPara<T> OP = new ObjectPara<T>(obj);        //        XmlNode root = xmlDoc.SelectSingleNode(Myroot);//查找<game data>        XmlNode Myroots = root.SelectSingleNode(OP.ObjName);//查询对象表        if (Myroots == null) {            Myroots = xmlDoc.CreateElement(OP.ObjName);            root.AppendChild(Myroots);        }        //以对象表为根,创建一个以ID为根的子根        XmlNode node = Myroots.SelectSingleNode(OP.GetKeyValue(ObjectID).ToString());        if (node != null) {//如果待插入的对象已经存在,则将此数据删除后,再重新插入            Delete<T>(obj);            Insert<T>(obj);            return;        }        XmlElement xe1 = xmlDoc.CreateElement(OP.GetKeyValue(ObjectID).ToString());//创建一个<data>节点        for (int i = 0; i < OP.cols.Length; i++)        {                        XmlElement xe = xmlDoc.CreateElement(OP.cols[i]);            xe.InnerText = OP.values[i];            xe1.AppendChild(xe);        }        if (Myroots == null)        {            Myroots = xmlDoc.CreateElement(OP.ObjName);            root.AppendChild(Myroots);        }        else        {            Myroots.AppendChild(xe1);        }        //添加到<bookstore>节点中        xmlDoc.Save(PATH);        OP = null;    }    public List<T> SelectAll<T>(T obj)    {        List<T> list = new List<T>();        ObjectPara<T> OP = new ObjectPara<T>(obj);                XmlNode root = xmlDoc.SelectSingleNode(Myroot);//查找<game data>        XmlNode Myroots = root.SelectSingleNode(OP.ObjName);//查询对象表        XmlNodeList nodes = Myroots.ChildNodes;//获取对象的所有子对象        foreach (XmlNode node in nodes)//        {            XmlNodeList lis = node.ChildNodes;//获取每个对象的字段            T o = obj;            int count = lis.Count;            string[] values = new string[count];            for (int i = 0; i < lis.Count; i++) {                values[i] = lis.Item(i).InnerText.Trim();            }            o = OP.GetObject(values);            list.Add(o);                    }        return list;    }    public T Select<T>(T obj)    {        ObjectPara<T> OP = new ObjectPara<T>(obj);        XmlNode root = xmlDoc.SelectSingleNode(Myroot);//查找<game data>        XmlNode Myroots = root.SelectSingleNode(OP.ObjName);//查询对象表        XmlNode node = Myroots.SelectSingleNode(OP.GetKeyValue(ObjectID).ToString());        //获取指定列为根的根元素        if (node != null)        {            XmlNodeList list = node.ChildNodes;//获取根的所有字段            int count = list.Count;            string[] values = new string[count];            for (int i = 0; i < list.Count; i++)            {//成员变量                //将遍历出的值赋予数组                values[i] = list.Item(i).InnerText.Trim();            }            obj = OP.GetObject(values);        }        else {            obj = default(T);            MyTool.P(213);        }         return obj;    }    public void Update<T>(T obj)    {        ObjectPara<T> OP = new ObjectPara<T>(obj);        //        XmlNode root = xmlDoc.SelectSingleNode(Myroot);//查找<game data>        XmlNode Myroots = root.SelectSingleNode(OP.ObjName);//查询对象表        XmlNode node = Myroots.SelectSingleNode(OP.GetKeyValue(ObjectID).ToString());        if (node != null)        {            XmlNodeList xnl = node.ChildNodes;            for (int i = 0; i < xnl.Count;i++ )            {//成员变量                //将遍历出的值赋予数组                xnl.Item(i).InnerText = OP.values[i];            }            xmlDoc.Save(PATH);        }    }    public void Update<T>(T obj, string key)    {        //插入一个对象        //对象有字段,属性值        //利用数据的特点,即名称不同,优化查询速度,具体的做法为,将属性值作为子根操作。        ObjectPara<T> OP = new ObjectPara<T>(obj);        //        XmlNode root = xmlDoc.SelectSingleNode(Myroot);//查找<game data>        XmlNode Myroots = root.SelectSingleNode(OP.ObjName);//查询对象表        XmlNode node = Myroots.SelectSingleNode(OP.GetKeyValue(ObjectID).ToString());        if (node != null)        {            //找到名为name的对象            XmlNode xl = node.SelectSingleNode(key);//找到字段            xl.InnerText = OP.GetKeyValue(key).ToString();            xmlDoc.Save(PATH);        }    }    public void Delete<T>(T obj)    {        ObjectPara<T> OP = new ObjectPara<T>(obj);        XmlNode root = xmlDoc.SelectSingleNode(Myroot);//查找<game data>        XmlNode Myroots = root.SelectSingleNode(OP.ObjName);//查询对象表        XmlNode node = Myroots.SelectSingleNode(OP.GetKeyValue(ObjectID).ToString());        if (node != null)        {            node.RemoveAll();            Myroots.RemoveChild(node);            xmlDoc.Save(PATH);        }    }    }

因为xml的结构我们要动态生成的,不需要专门针对某一个类写操作语句。如何动态就靠解析类完成了。好,下面是这个解析类,也就是用反射,本身并不难,关键是如何运用。特别声明的是,因为我操作的数据包含数组,而且数组只用到了字符数组,整型数组,以及浮点数组,所以只写了这三个数组的解析。其他类型数组你看需求自己定义:
using System;using System.Reflection;using UnityEngine;using System.Collections.Generic;using System.Runtime.InteropServices;public class ObjectPara<T>{    public string ObjName;//待解析的类的名称    public string[] cols;//类的成员变量    public string[] values;//成员变量对应的值    public PropertyInfo[] info;//反射获取类的属性    public Type objtype;//待解析类型    public T obj;//泛型对象    public T GetObject(string[] values)    {        T _obj = obj;        for (int i = 0; i < info.Length; i++)        {            if (objtype.GetProperty(cols[i]).PropertyType.IsArray)            {                                Type type = objtype.GetProperty(cols[i]).PropertyType;                string[] vale = values[i].Split(new char[] { ',' });                if (type == typeof(string[]))                {                    info[i].SetValue(_obj, vale, null);                }                else if (type == typeof(int[]))                {                    int[] va = new int[vale.Length];                    for (int j = 0; j < va.Length; j++)                    {                        va[j] = int.Parse(vale[j]);                    }                    info[i].SetValue(_obj, va, null);                }                else if (type == typeof(float[]))                {                    float[] va = new float[vale.Length];                    for (int j = 0; j < va.Length; j++)                    {                        va[j] = float.Parse(vale[j]);                    }                    info[i].SetValue(_obj, va, null);                }                //MyTool.P(values[i]);            }            else            {                info[i].SetValue(_obj, Convert.ChangeType(values[i], info[i].PropertyType), null);            }        }        return _obj;    }    public ObjectPara()    {    }    public ObjectPara(T obj)    {        this.obj = obj;        AnalyzeObject();    }    public void AnalyzeObject()//解析对象    {        //获取对象的名称,字段,以及值,以字符串数组的形式存储        objtype = obj.GetType();        ObjName = objtype.Name;        info = objtype.GetProperties();        cols = new string[info.Length];        values = new string[info.Length];        for (int i = 0; i < info.Length; i++)        {            cols[i] = info[i].Name;            string value = "";            if (objtype.GetProperty(cols[i]).PropertyType.IsArray)            {                if (objtype.GetProperty(cols[i]).GetValue(obj, null) != null)                {                    Type type = objtype.GetProperty(cols[i]).PropertyType;                    if (type == typeof(string[]))                    {                        MyTool.P(value);                        string[] ob = objtype.GetProperty(cols[i]).GetValue(obj, null) as string[];                        if (ob != null)                        {                            foreach (var o in ob)                            {                                value += o + ",";                            }                            //value = value.Substring(0, value.Length-2);                            value = value.TrimEnd(new char[] { ',' });                        }                    }                    else if (type == typeof(int[]))                    {                        int[] ob = objtype.GetProperty(cols[i]).GetValue(obj, null) as int[];                        if (ob != null)                        {                            foreach (var o in ob)                            {                                value += o + ",";                            }                            //value = value.Substring(0, value.Length-2);                            value = value.TrimEnd(new char[] { ',' });                        }                    }                    else if (type == typeof(float[]))                    {                        float[] ob = objtype.GetProperty(cols[i]).GetValue(obj, null) as float[];                        if (ob != null)                        {                            foreach (var o in ob)                            {                                value += o + ",";                            }                            //value = value.Substring(0, value.Length-2);                            value = value.TrimEnd(new char[] { ',' });                        }                    }                }            }            else            {                value = Convert.ToString(objtype.GetProperty(cols[i]).GetValue(obj, null));            }            //MyTool.P(value);            values[i] = value;        }    }    public System.Object GetKeyValue(string col)    {        return (objtype.GetProperty(col).GetValue(obj, null));    }}

好了,以上就是设计万能xml的部分,如何使用呢?

很简单,你先写一个类,这个类很简单,或者说为了简单,只有一个成员变量。这样可以统一对所有对象进行操作,

public class GameData  {    private string iD;    public string ID    {        get { return iD; }        set { iD = value; }    }}

然后随便写一个实体类,例如Person

public class MyPerson :GameData{    private string name;    public string Name    {        get { return name; }        set { name = value; }    }    private int sort;    public int Sort    {        get { return sort; }        set { sort = value; }    }    private float life;    public float Life    {        get { return life; }        set { life = value; }    }}

接下来就是一个简单的测试类了,我就不传代码了。各位自己测试:

MyPerson p = new Myperson();

p.ID="lihua";

……

MyDataBase.Insert(p);添加

MyDataBase.Delete(p);删除

……

注意一下的问题,不要以为复制完代码就可以运行,主要是目录路径问题,如果你实在搞不定,直接先在Assent目录下建立一个路径DataBase,然后再建一个GameData.xml。好,接下来看你发挥。

本文原帖http://www.cnblogs.com/jqg-aliang/p/4597135.html。转载请申明出处,谢谢


0 0
原创粉丝点击