简单的xml数据库设计
我的需求
有时候系统需要存储一些简单的关系型属性,不考虑并发,不考虑性能(一次操作在几ms),数据库没有其他依赖引用,拿过来就可以用
为什么选xml作为数据库?
- 可读性好
- 实体的对应关系不严格 ,
二进制序列化实体改动后不能读取以前序列化的数据,而且实体上面需要贴可序列化标签
数据库功能
- 无侵入存储实体,可存储poco对象,不需要在实体上面贴标签或继承什么
- 单例操作内存数据,只有初始化或者写入的时候才会读写文件,其他时候操作内存中的数据
使用指南
* 定义实体(public)
public class Friend{}
* 定义实体操作类,继承XmlDb<T>
public class FriendDbSet : XmlDb<Friend>
{
static FriendDbSet _instance = new FriendDbSet();
public static FriendDbSet GetInstance()
{
return _instance;
}
}
* 操作实体
Friend friend = new Friend() { Id = "1", name = "何仙姑" };
Friend friend2 = new Friend() { Id = "1", name = "何仙姑2" };
//添加
FriendDbSet.GetInstance().Add(friend2);
//删除
FriendDbSet.GetInstance().Remove(r => r.Id == "1");
//修改
friend.name = "何惠惠";
FriendDbSet.GetInstance().UpdateByIdOrKey(friend);
//查询
var result = FriendDbSet.GetInstance().ToList().Where(r => r.name.StartsWith("何"));
>也可以不定义实体操作类直接进行如下操作
>XmlDb<Friend>.GetInstance().Add(u);//增加
>XmlDb<Friend>.GetInstance().Remove(r=>r.Age>1000);//根据条件删除
>XmlDb<Friend>.GetInstance().Remove("key");//根据key或id删除
>XmlDb<Friend>.GetInstance().UpdateByIdOrKey(new User() { });//修改
>XmlDb<Friend>.GetInstance().ToList();//查询全部
>XmlDb<Friend>.GetInstance().Find("key");//查询单个
代码(使用单例模式,模版方法模式)
public class XmlDb where T : new()
{
private static XmlDb instance = new XmlDb();
public static XmlDb<T> GetInstance()
{
return instance;
}
private List<T> entityList = new List<T>();
public XmlDb()
{
this.SetDbFile();
this.ReadDb();
}
private string dbFile;
private string Dbfile
{
get { return dbFile; }
set
{
if (!string.IsNullOrEmpty(value) && !value.Equals(dbFile))
{
this.entityList.Clear();
}
dbFile = value;
this.ReadDb();
}
}
protected virtual void ReadDb()
{
if (File.Exists(this.Dbfile))
{
XmlSerializer ks = new XmlSerializer(typeof(List<T>));
Stream reader = new FileStream(this.Dbfile, FileMode.Open, FileAccess.ReadWrite);
this.entityList = ks.Deserialize(reader) as List<T>;
reader.Close();
}
else
{
this.entityList = new List<T>();
}
}
protected virtual void SetDbFile()
{
string folder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "storage", "litedb");
if (!Directory.Exists(folder)) Directory.CreateDirectory(folder);
Type type = typeof(T);
if (string.IsNullOrEmpty(this.Dbfile))
{
//获取全名称签名,防止类名重复
string md5Sign = BitConverter.ToString(MD5.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(type.FullName))).Replace("-", "");
this.Dbfile = Path.Combine(folder, type.Name + "_" + md5Sign + ".xml");
}
}
protected virtual void WriteDb()
{
//异常处理
string tempFileName = this.dbFile.Replace(".xml", "_Temp.xml");
try
{
XmlSerializer ks = new XmlSerializer(typeof(List<T>));
FileInfo fi = new FileInfo(this.Dbfile);
var dir = fi.Directory;
if (!dir.Exists)
{
dir.Create();
}
//缓存数据防止读写失败
if (fi.Exists)
{
fi.CopyTo(tempFileName, true);
}
Stream writer = new FileStream(this.Dbfile, FileMode.Create, FileAccess.ReadWrite);
ks.Serialize(writer, this.entityList);
writer.Close();
//删除缓存数据
if (File.Exists(tempFileName))
{
File.Delete(tempFileName);
}
UpdateSchema();
}
catch (Exception ex)
{
//恢复数据
throw ex;
}
}
/// <summary>
/// 更新数据的元数据信息
/// </summary>
private void UpdateSchema()
{
string root = Path.GetDirectoryName(this.Dbfile);
var files = Directory.GetFiles(root, "*.xml").Where(r => !r.EndsWith("schema.xml")).Select(r => Path.GetFileName(r));
//构建xml并存储
string schemaFile = Path.Combine(root, "schema.xml");
XDocument xdoc = new XDocument();
XElement xmlroot = new XElement("root");
xdoc.Add(xmlroot);
foreach (var item in files)
{
xdoc.Root.Add(new XElement("fileName", item));
}
xdoc.Save(schemaFile);
}
/// <summary>
/// 根据主键或Id获取实体对象
/// </summary>
/// <param name="KeyOrId"></param>
/// <returns></returns>
public T Find(string KeyOrId)
{
Type t = typeof(T);
foreach (var inst in this.entityList)
{
foreach (PropertyInfo pro in t.GetProperties())
{
var keyattr = pro.GetCustomAttribute(typeof(System.ComponentModel.DataAnnotations.KeyAttribute), false);
if (keyattr != null || pro.Name.ToLower() == "id")
{
if (pro.GetValue(inst, null)?.ToString() == KeyOrId)
{
return inst;
}
}
}
}
return default(T);
}
public void Add(T entity)
{
this.entityList.Add(entity);
this.WriteDb();
}
public void AddRange(List<T> list)
{
this.entityList.AddRange(list);
this.WriteDb();
}
public List<T> ToList()
{
this.ReadDb();
return entityList;
}
/// <summary>
/// 根据条件移除元素
/// </summary>
/// <param name="filters"></param>
public void Remove(Predicate<T> filters)
{
this.entityList.RemoveAll(filters);
this.WriteDb();
}
/// <summary>
/// 根据key或id移除元素
/// </summary>
/// <param name="filters"></param>
public void Remove(string KeyOrId)
{
Type t = typeof(T);
T entity = default(T);
foreach (var inst in this.entityList)
{
foreach (PropertyInfo pro in t.GetProperties())
{
var keyattr = pro.GetCustomAttribute(typeof(System.ComponentModel.DataAnnotations.KeyAttribute), false);
if (keyattr != null || pro.Name.ToLower() == "id")
{
if (pro.GetValue(inst, null)?.ToString() == KeyOrId)
{
entity = inst;
goto FinishLoop;
}
}
}
}
FinishLoop:
entityList.Remove(entity);
this.WriteDb();
}
public void UpdateByIdOrKey(T entity)
{
Type t = typeof(T);
string id = string.Empty;
foreach (PropertyInfo pro in t.GetProperties())
{
var keyattr = pro.GetCustomAttribute(typeof(System.ComponentModel.DataAnnotations.KeyAttribute), false);
if (keyattr != null || pro.Name.ToLower() == "id")
{
id = pro.GetValue(entity, null)?.ToString();
break;
}
}
this.Remove(id);
this.Add(entity);
}
/// <summary>
/// 清空列表
/// </summary>
/// <param name="filters"></param>
public void Clear()
{
entityList.Clear();
this.WriteDb();
}
}
简单的xml数据库设计的更多相关文章
- NetCore微服务简单流程审批数据库设计及后台服务开发
1.数据库设计 -- ---------------------------- -- Table structure for TBase_Flow -- ----------------------- ...
- day39 python 学习 数据库学习 五个约束,数据库设计(一对一,一对多等等)
删除重复数据: 注意数据库不能又查又删 *******#删除作者为重复数据并保留ID最大的是数据 delete from ren where author in (select * from(sel ...
- MySQL 约束和数据库设计
1.MySQL 约束: 1.约束的概念: 约束是一种限制,它通过对表的行或列的数据做出限制,来确保表的数据的完整性.唯一性. MySQL中,常用的几种约束: 约束类型: 非空 主键 唯一 外键 默认值 ...
- 基于XML数据库的学生信息管理系统的设计与实现
本项目是在学习之余写的,主要用来练习MVC+DAO的分层设计思想,项目基于一个简单的XML学生数据库,使用XML作为数据库的原因是其十分的小巧与方便,使用dom4j即可进行方便的解析.因为这段时间课程 ...
- 数据库设计 Step by Step (1)——扬帆启航
引言:一直在从事数据库开发和设计工作,也看了一些书籍,算是略有心得.很久之前就想针 对关系数据库设计进行整理.总结,但因为种种原因迟迟没有动手,主要还是惰性使然.今天也算是痛下决心开始这项卓绝又令我兴 ...
- mysql 数据库设计(转)
本规范适用于mysql 5.1或以上版本使用 数据库范式 第一范式(1NF)确保每列保持原子性 第一范式(1NF):数据库表的每一列都是不可分割的原子数据项,而不能是集合,数组,记录等非原子数据项. ...
- 转载unity编辑器xml数据库插件
unity编辑器xml数据库插件 注:9月9日更新,其中MyXML.cs中有一句代码写错,查找功能失误,文中已经修改! 注:9月1日更新说明:xml存储结构,因为在用xml之前不知道正规的xml数据结 ...
- 数据库设计中的Soft Delete模式
最近几天有点忙,所以我们今天来一篇短的,简单地介绍一下数据库设计中的一种模式——Soft Delete. 可以说,该模式毁誉参半,甚至有非常多的人认为该模式是一个Anti-Pattern.因此在本篇文 ...
- 使用django开发博客过程记录1——数据库设计
1.数据库设计 2.插入测试数据 3.配置相关问题 1.数据库设计 数据库有简单的三张表:Article.Category.Tag以下是代码 # -*- coding:utf-8 -*- from _ ...
随机推荐
- 思维导图学《JVM 虚拟机规范》
目录 工具 虚拟机实现 class 文件结构 字节码指令 其他 虚拟机结构 公众号 coding 笔记.点滴记录,以后的文章也会同步到公众号(Coding Insight)中,希望大家关注_ 公众号 ...
- Kubernetes中Service的使用
目录 简介 1. Service资源定义 1.1 Service Type ClusterIP 无头service NodePort sessionAffinity实现源地址session绑定 简介 ...
- Python中format_map与format字符串格式化的区别
在Python3中使用format和format_map方法都可以进行字符串格式化,但format是一种所有情况都能使用的格式化方法,format_map仅使用于字符串格式中可变数据参数来源于字典等映 ...
- Python中splitlines方法判断文本中一行结束除了回车换行符是否还有其他字符?
Python中splitlines([keepends])方法用于返回由原字符串中各行组成的列表,在行边界的位置拆分. 如果keepends=True,结果列表中包含行边界,否则不包含 行边界的字符. ...
- PyQt(Python+Qt)学习随笔:Qt Designer中QAbstractButton派生按钮部件的icon属性和iconSize属性
icon属性 icon属性保存按钮上展示的图标,图标的缺省大小由图形界面的样式决定,但可以通过 iconSize 属性进行调整. 图标的几种子属性状态的含义与QWidget的windowIcon属性相 ...
- ABP框架使用Mysql数据库,以及基于SQLServer创建Mysql数据库的架构和数据
ABP默认的数据库是SQLServer,不过ABP框架底层是EF框架,因此也是很容易支持其他类型的数据库的,本篇随笔介绍在ABP框架使用Mysql数据库,以及基于SQLServer创建MySql数据库 ...
- CentOS下安装SublimeText
1.Install the GPG key: sudo rpm -v --import https://download.sublimetext.com/sublimehq-rpm-pub.gpg 2 ...
- 总结下flask中的宏、Jinjia2语法
这几天学的东西比较多,时间又有点不够用,趁着快吃饭了,赶紧总结总结. 00x1 宏: 如果学过C语言的童鞋,可能知道宏在C语言里面是一个定义一个固定参数的变量.在flask里面,宏是相当于一个函数的作 ...
- 我摊牌了,大厂面试Linux就这5个问题
说真的,这就是<我想进大厂>系列第八篇,但是Linux的问题确实很少,就这样,强行编几个没有营养的问题也没啥意义. 1.CPU负载和CPU利用率的区别是什么? 首先,我们可以通过uptim ...
- 学习JUC源码(1)——AQS同步队列(源码分析结合图文理解)
前言 最近结合书籍<Java并发编程艺术>一直在看AQS的源码,发现AQS核心就是:利用内置的FIFO双向队列结构来实现线程排队获取int变量的同步状态,以此奠定了很多并发包中大部分实现基 ...