SharpFileDB - a file database for small apps

SharpFileDB - a file database for small apps

本文中文版在此处

I‘m not an expert of database. Please feel free to corect my mistakes.

This article (http://www.cnblogs.com/gaochundong/archive/2013/04/24/csharp_file_database.html) helpes a lot. Thank you!

目标(Goal)

I‘ve decided to write a micro database library that spports 10 thousand level applications.

It‘s better not to rely on other drives or tools in case of high difficulty in deployment. After all, it‘s a small database for a small application.

It‘s a DLL from totally C# codes. It‘s easy for reading and using.

It supports CRUD of course.

It doesn‘t use any SQL. I‘m not familiar with SQL and I don‘t like it. And it‘s not necessary to use SQL here.

It saves data via plain text files or binary files. It‘s convenient to use plain text files when developing and debugging codes. And it‘s safer to use binary files at deployment time.

So, simply, it‘s a micro database library that uses no SQL, files as storage form and totally C# to implement a CRUD system. Let‘s name the library SharpFileDB.

I‘ve put the newest project on Github. All codes in the library are noted in both chinese and engilsh. I hope that will help to communicate.

设计草图(sketch)

使用场景(User Scene)

The typical user scene of SharpFileDB is as follows.

 1                 // common cases to use SharpFileDB.
 2                 FileDBContext db = new FileDBContext();
 3
 4                 Cat cat = new Cat();
 5                 cat.Name = "xiao xiao bai";
 6                 db.Create(cat);
 7
 8                 Predicate<Cat> pre = new Predicate<Cat>(x => x.Name == "xiao xiao bai");
 9                 IList<Cat> cats = db.Retrieve(pre);
10
11                 cat.Name = "xiao bai";
12                 db.Update(cat);
13
14                 db.Delete(cat);

This routine contains lines that create a database and uses CRUD operations.

Let‘s start the first version of SharpFileDB according to this user scene.

表vs类型(Table vs Type)

Let‘s take the type ‘Cat‘ as an example.

 1     /// <summary>
 2     /// demo file object
 3     /// </summary>
 4     public class Cat : FileObject
 5     {
 6         public string Name { get; set; }
 7         public int Legs { get; set; }
 8
 9         public override string ToString()
10         {
11             return string.Format("{0}, Name: {1}, Legs: {2}", base.ToString(), Name, Legs);
12         }
13     }

The type ‘Cat‘ is equivalent to a ‘Table‘ in a relational database.

An instance of ‘Cat‘ is equivalent to a record of a ‘Table‘.

Lets‘ call types like ‘Cat‘ a table-type.

全局唯一的主键(global unique main key)

We need a global unique main key for every instance of a table-type to diffentiate them. So let‘s do this in an abstract class.

 1     /// <summary>
 2     /// 可在文件数据库中使用CRUD操作的所有类型的基类。
 3     /// Base class for all classed that can use CRUD in SharpFileDB.
 4     /// </summary>
 5     [Serializable]
 6     public abstract class FileObject
 7     {
 8         /// <summary>
 9         /// 主键.
10         /// main key.
11         /// </summary>
12         public Guid Id { get; set; }
13
14         /// <summary>
15         /// 创建一个文件对象,并自动为其生成一个全局唯一的Id。
16         /// <para>Create a <see cref="FileObject"/> and generate a global unique id for it.</para>
17         /// </summary>
18         public FileObject()
19         {
20             this.Id = Guid.NewGuid();
21         }
22
23         public override string ToString()
24         {
25             return string.Format("Id: {0}", this.Id);
26         }
27     }

数据库(FileDBContext)

All table-types‘ CRUD operations are done in a FileDBContext.

  1     /// <summary>
  2 /// 文件数据库。
  3     /// Represents a file database.
  4     /// </summary>
  5     public class FileDBContext
  6     {
  7         #region Fields
  8
  9         /// <summary>
 10         /// 文件数据库操作锁
 11         /// <para>database operation lock.</para>
 12         /// </summary>
 13         protected static readonly object operationLock = new object();
 14
 15         /// <summary>
 16         /// 文件数据库
 17         /// <para>Represents a file database.</para>
 18         /// </summary>
 19         /// <param name="directory">数据库文件所在目录<para>Directory for all files of database.</para></param>
 20         public FileDBContext(string directory = null)
 21         {
 22             if (directory == null)
 23             {
 24                 this.Directory = Environment.CurrentDirectory;
 25             }
 26             else
 27             {
 28                 Directory = directory;
 29             }
 30         }
 31
 32         #endregion
 33
 34         public override string ToString()
 35         {
 36             return string.Format("@: {0}", Directory);
 37         }
 38
 39         #region Properties
 40
 41         /// <summary>
 42         /// 数据库文件所在目录
 43         /// <para>Directory of database files.</para>
 44         /// </summary>
 45         public virtual string Directory { get; protected set; }
 46
 47         #endregion
 48
 49
 50         protected string Serialize(FileObject item)
 51         {
 52             using (StringWriterWithEncoding sw = new StringWriterWithEncoding(Encoding.UTF8))
 53             {
 54                 XmlSerializer serializer = new XmlSerializer(item.GetType());
 55                 serializer.Serialize(sw, item);
 56                 string serializedString = sw.ToString();
 57
 58                 return serializedString;
 59             }
 60         }
 61
 62         /// <summary>
 63         /// 将字符串反序列化成文档对象
 64         /// </summary>
 65         /// <typeparam name="TDocument">文档类型</typeparam>
 66         /// <param name="serializedFileObject">字符串</param>
 67         /// <returns>
 68         /// 文档对象
 69         /// </returns>
 70         protected TFileObject Deserialize<TFileObject>(string serializedFileObject)
 71             where TFileObject : FileObject
 72         {
 73             if (string.IsNullOrEmpty(serializedFileObject))
 74                 throw new ArgumentNullException("data");
 75
 76             using (StringReader sr = new StringReader(serializedFileObject))
 77             {
 78                 XmlSerializer serializer = new XmlSerializer(typeof(TFileObject));
 79                 object deserializedObj = serializer.Deserialize(sr);
 80                 TFileObject fileObject = deserializedObj as TFileObject;
 81                 return fileObject;
 82             }
 83         }
 84
 85         protected string GenerateFileFullPath(FileObject item)
 86         {
 87             string path = GenerateFilePath(item.GetType());
 88             string name = item.GenerateFileName();
 89             string fullname = Path.Combine(path, name);
 90             return fullname;
 91         }
 92
 93         /// <summary>
 94         /// 生成文件路径
 95         /// </summary>
 96         /// <typeparam name="TDocument">文档类型</typeparam>
 97         /// <returns>文件路径</returns>
 98         protected string GenerateFilePath(Type type)
 99         {
100             string path = Path.Combine(this.Directory, type.Name);
101             return path;
102         }
103
104         #region CRUD
105
106         /// <summary>
107         /// 增加一个<see cref="FileObject"/>到数据库。这实际上创建了一个文件。
108         /// <para>Create a new <see cref="FileObject"/> into database. This operation will create a new file.</para>
109         /// </summary>
110         /// <param name="item"></param>
111         public virtual void Create(FileObject item)
112         {
113             string fileName = GenerateFileFullPath(item);
114             string output = Serialize(item);
115
116             lock (operationLock)
117             {
118                 System.IO.FileInfo info = new System.IO.FileInfo(fileName);
119                 System.IO.Directory.CreateDirectory(info.Directory.FullName);
120                 System.IO.File.WriteAllText(fileName, output);
121             }
122         }
123
124         /// <summary>
125         /// 检索符合给定条件的所有<paramref name="TFileObject"/>。
126         /// <para>Retrives all <paramref name="TFileObject"/> that satisfies the specified condition.</para>
127         /// </summary>
128         /// <typeparam name="TFileObject"></typeparam>
129         /// <param name="predicate">检索出的对象应满足的条件。<para>THe condition that should be satisfied by retrived object.</para></param>
130         /// <returns></returns>
131         public virtual IList<TFileObject> Retrieve<TFileObject>(Predicate<TFileObject> predicate)
132             where TFileObject : FileObject
133         {
134             IList<TFileObject> result = new List<TFileObject>();
135             if (predicate != null)
136             {
137                 string path = GenerateFilePath(typeof(TFileObject));
138                 string[] files = System.IO.Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories);
139                 foreach (var item in files)
140                 {
141                     string fileContent = File.ReadAllText(item);
142                     TFileObject deserializedFileObject = Deserialize<TFileObject>(fileContent);
143                     if (predicate(deserializedFileObject))
144                     {
145                         result.Add(deserializedFileObject);
146                     }
147                 }
148             }
149
150             return result;
151         }
152
153         /// <summary>
154         /// 更新给定的对象。
155         /// <para>Update specified <paramref name="FileObject"/>.</para>
156         /// </summary>
157         /// <param name="item">要被更新的对象。<para>The object to be updated.</para></param>
158         public virtual void Update(FileObject item)
159         {
160             string fileName = GenerateFileFullPath(item);
161             string output = Serialize(item);
162
163             lock (operationLock)
164             {
165                 System.IO.FileInfo info = new System.IO.FileInfo(fileName);
166                 System.IO.Directory.CreateDirectory(info.Directory.FullName);
167                 System.IO.File.WriteAllText(fileName, output);
168             }
169         }
170
171         /// <summary>
172         /// 删除指定的对象。
173         /// <para>Delete specified <paramref name="FileObject"/>.</para>
174         /// </summary>
175         /// <param name="item">要被删除的对象。<para>The object to be deleted.</para></param>
176         public virtual void Delete(FileObject item)
177         {
178             if (item == null)
179             {
180                 throw new ArgumentNullException(item.ToString());
181             }
182
183             string filename = GenerateFileFullPath(item);
184             if (File.Exists(filename))
185             {
186                 lock (operationLock)
187                 {
188                     File.Delete(filename);
189                 }
190             }
191         }
192
193         #endregion CRUD
194
195     }

FileDBContext

文件存储方式(Way to store files)

SharpFileDB creates a directory for every table-types in the database‘s folder. Every instance of a table-type are stored in its respective directory as a single XML file. The file‘s name is same with the instance‘s Id.

下载(Download)

I‘ve put the project on github(https://github.com/bitzhuwei/SharpFileDB/) and you are welcom to try, create issues and fork it.

PS: I think this small file database library can help some people. It‘s where we are that needs us.

时间: 2024-10-03 22:32:31

SharpFileDB - a file database for small apps的相关文章

小型文件数据库 (a file database for small apps) SharpFileDB

小型文件数据库 (a file database for small apps) SharpFileDB For english version of this article, please click here. 我并不擅长数据库,如有不当之处,请多多指教. 本文参考了(http://www.cnblogs.com/gaochundong/archive/2013/04/24/csharp_file_database.html),在此表示感谢! 目标(Goal) 我决定做一个以支持小型应用(

EBS R12 修改 apps 密码[Z]

注意:修改密码时应保证所有用户已退出, 最好是关闭应用实例.不用关闭数据库.在修改密码之前一定要改备下数据库中的FND_ORACLE_USERID和FND_USER表.FNDCPASS工具会自动把APPS用户的密码和APPLSYS用户的密码和APPLSYS用户的密码同步设置成一样的.在修改完APPLSYS和APPS用户的密码后, 需要重新启动并发管理器.在修改完APPLSYS和APPS用户的密码后,要求将已经处在登录状态的用户完全退出, 然后重新登录.修改APPS用户的密码不支持直接在数据库中使

Database(Mysql)发版控制二

author:skate time:2014/08/18 Database(Mysql)发版控制 The Liquibase Tool related Database 一.Installation & Configration 二.Advanced Usage of the Liquibase 三.Frequently Questions 二.Advanced Usage of the Liquibase 1.实际场景模拟 实际需求:需要把不同环境的不同分支的数据库变更合并,并按需求应用或回滚

Inno Setup connection to the database and create

原文 Inno Setup connection to the database and create Description: the first half of this program in Inno Setup instance inside there, behind the database backup and restore inside the instance is not easy to find online, I spent a great difficulty sen

Deploying JRE (Native Plug-in) for Windows Clients in Oracle E-Business Suite Release 12 (文档 ID 393931.1)

In This Document Section 1: Overview Section 2: Pre-Upgrade Steps Section 3: Upgrade and Configuration Section 4: Post-installation Steps Section 5: Known Issues Section 6: Appendices This document covers the procedure to upgrade the version of the J

PAN-OS 6.1 Open Source Software (OSS) Listing

https://www.paloaltonetworks.com/documentation/oss-listings/oss-listings/pan-os-oss-listings/pan-os-6-1-open-source-software-oss-listing NAME HOW INTEGRATED VERSION LICENSE TYPE USAGE MAKEDEV Standalone apps/libraries 3.23 GPLv2 A program used for cr

EBS Custom Password Rules

https://blogs.oracle.com/manojmadhusoodanan/entry/custom_password_rules Custom Password Rules By Manoj Madhusoodanan-Oracle on Apr 30, 2012 Every organization has certain policies in the login credentials.Oracle Applications has a flexibility to impl

C++开源库集合

| Main | Site Index | Download | mimetic A free/GPL C++ MIME Library mimetic is a free/GPL Email library (MIME) written in C++ designed to be easy to use and integrate but yet fast and efficient. It is based on the C++ standard library and heavily us

How to Create a Java Concurrent Program

In this Document   Goal   Solution   Overview   Steps in writing Java Concurrent Program   Template Program:   Program Logic   Program Parameters   Database Operations   Setting request Completion Status   Register executable   Register Concurrent Pr