设为首页 收藏本站
查看: 1598|回复: 0

Windows 8 Metro开发疑难杂症(四)——(伪)数据库

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2015-5-22 11:48:47 | 显示全部楼层 |阅读模式
  做个windows 8开发的或者正要做windows 8开发的需要知道一点是,在win8目前的SDK中是不支持本地数据库的。据说现在有win8版的sqllite数据库了,我没用过,不过就算真的有也没关系,我这篇博客不是讲如果用使用数据库的,而是讲如果利用现有的API和资源做一个自定义的数据库。如果你觉得使用SQllite够用的话那你可以跳过这篇文章。
  首先win8是没有本地数据库的(当前win8SDK版本),其次我们的APP可能就是需要数据库来存放一些客户端的东西,那么目前的唯一的方法就是自己做数据库,其实这里说自己做数据库说的有点大,因为我这里给大家介绍的不是说自己开发一个类似sqllite那种真正的数据库(我没这本事),而是给大家介绍一种方法可以达到类似WP7 中SQL CE那样使用习惯和使用方法的伪数据库(也可以称为山寨版数据库),如果你用过WP7的SQL CE的数据库,你会对我介绍的方法很熟悉,用起来会很顺手。
  废话不多说,进入正题。
  首先数据库的存储方式肯定不是存储在内存里的,而是以文件的形式存储在“硬盘”上的。另外,既然是数据库,那么数据在内存中的状态应该是以集合形式存储的。这样我们的问题就是,把集合以文件的形式存储,如何达到这个目的,很显然就是利用序列化和反序列化。目前数据的序列化有两种方式,一个是XML,一个JSON,我个人推荐Json,速度快,序列化后的体积也小。
  下面正是进入编码阶段,新建一个项目叫做DatabaseTest,然后新建一个类库项目Database,记得引用下。先对DataBase进行修改,既然我们的数据库不是真数据库,那么我就取名叫FakeDatabase,这是一个基类,所有以后用到数据库的地方必须继承自这个类。
  先不管FakeDatabase,继续新建一个类叫Table,继承自ObservableCollection,这个类是一个密封类,看名字就知道数数据库中的表,代码如下:



public sealed class Table : ObservableCollection
{
internal Table()
{
}
protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnCollectionChanged(e);
IsChanged = true;
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)
{
foreach (INotifyPropertyChanged item in e.NewItems)
{
item.PropertyChanged += item_PropertyChanged;
}
}
}
//指示表中的数据是否发生更改
internal bool IsChanged;
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
IsChanged = true;
}
}
  然后回到FakeDataBase。首先我们的目标是做一个在使用方法和使用习惯上类似WP7 SQLCe的数据库,那么就是说在新建数据库的时候,只要在数据库类中添加相应的Table就行了。我不说具体实现过程了,直接贴代码好了:



  ///
/// 伪数据库基类
///
public abstract class FakeDataBase
{
private string DBAddress;
public FakeDataBase(string dbAddress)
{
this.DBAddress = dbAddress;
}
private bool isInitialed;
///
/// 初始化数据库中的数据
///
///
public virtual async Task InitialBatabaseAsync()
{
if (!isInitialed)
{
Type t = this.GetType();
foreach (var item in t.GetTypeInfo().DeclaredFields)
{
if (item.FieldType.Name == "Table`1")
{
string address = DBAddress + "_" + item.Name;
var value = await DeserializeObjectFromFile(address, item.FieldType);
if (value == null)
{
item.SetValue(this, CreateInstance(item.FieldType, null));
}
else
item.SetValue(this, value);
}
}
isInitialed = true;
}
}
///
/// 提交更改
///
///
public virtual async Task SubmitChanges()
{
Type t = this.GetType();
foreach (var item in t.GetTypeInfo().DeclaredFields)
{
var itemType = item.FieldType;
if (itemType.Name == "Table`1")
{
var info = itemType.GetTypeInfo().DeclaredFields.FirstOrDefault(c => c.Name == "IsChanged");
var table = item.GetValue(this);
var value = (bool)info.GetValue(table);
if (value)
{
string address = DBAddress + "_" + item.Name;
await SerializeObjectToFile(address, item.GetValue(this));
info.SetValue(table, false);
}
}
}
}

///
/// 根据文件名,将文件内容反序列化成某个对象
///
///
///
///
private async Task DeserializeObjectFromFile(string fileName, Type type)
{
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
StorageFile file = null;
object objTarget;
try
{
file = await storageFolder.GetFileAsync(fileName);
}
catch (Exception)
{
}
if (file == null)
{
objTarget = null;
}
else
{
string str = await FileIO.ReadTextAsync(file);
objTarget = JsonDeserialize(str, type);
}
return objTarget;
}
///
/// 将Json字符串反序列化成对象
///
///
///
///
private object JsonDeserialize(string str, Type type)
{
if (string.IsNullOrEmpty(str))
return null;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(type);
using (Stream stream = new MemoryStream(System.Text.UTF8Encoding.UTF8.GetBytes(str)))
{
return serializer.ReadObject(stream);
}
}
///
/// 将某个对象序列化成Json字符串
///
///
///
private static string JsonSerializer(object target)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(target.GetType());
using (Stream stream = new MemoryStream())
{
serializer.WriteObject(stream, target);
stream.Seek(0, SeekOrigin.Begin);
using (StreamReader reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
}

///
/// 将某个对象序列化成文件,如果传递的对象为null,那么删除原来的文件
///
///
///
///
private async Task SerializeObjectToFile(string fileName, object target)
{
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
StorageFile storageFile = null;
//如果target为null,那么删除文件
if (target == null)
{
storageFile = await storageFolder.GetFileAsync(fileName);
if (storageFile != null)
{
await storageFile.DeleteAsync();
}
return;
}
string str = JsonSerializer(target);
storageFile = await storageFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(storageFile, str);
}

///
/// 动态创建一个类型的对象
///
///
///
///
private object CreateInstance(Type t, object[] paramas)
{
int pCount = paramas == null ? 0 : paramas.Length;
foreach (var item in t.GetTypeInfo().DeclaredConstructors)
{
var p = item.GetParameters();
if (p.Length == pCount)
return item.Invoke(paramas);
}
throw new InvalidOperationException("没有找到合适的构造函数");
}
}
  上面两部分的代码已经实现了我们上面提到的目标。下面我就介绍下如何使用这个自己做的伪数据库。
  假如我们数据库中有一个用来存放用户信息的表,叫UserInfo,里面有name和age两个属性,那么新建一个UserInfo的类。



   [DataContract]
public class UserInfo : BindableBase
{
private string name;
[DataMember]
public string Name
{
get
{
return name;
}
set
{
base.SetProperty(ref name, value, "Name");
}
}
private int age;
[DataMember]
public int Age
{
get
{
return age;
}
set
{
base.SetProperty(ref age, value, "Age");
}
}
}
  
  然后就是创建我们的数据库了,叫做TestDatabase



public class TestDataBase:FakeDataBase
{
private const string DBAddress = "TestDataBase.db";
public TestDataBase()
: base(DBAddress)
{
}
public Table UserTable;
}
  至此,数据库已经创建完毕。
  下面讲下如何操作这个数据库。
  首先我们在使用数据库中数据库的时候一定要先初始化数据库,



   Data.TestDataBase db; db = new Data.TestDataBase();
await db.InitialBatabaseAsync();
  然后就是把数据库中的表绑定到列表控件



listview_userlist.ItemsSource = db.UserTable;
  往数据库中添加数据:



db.UserTable.Add(addUser);
await db.SubmitChanges();
  删除数据代码:



       db.UserTable.Remove(user);
await db.SubmitChanges();
  以上操作数据库的代码是不是看起来很熟悉?只要你用过WP7 的SQL CE,看到这些代码你肯定会很熟悉的。
界面代码我就不贴出来了,你可以直接下载源码查看的,下面贴一张运行图。
DSC0000.jpg
  现在说下这个伪数据库和WP7 SQLce比起来的优缺点:
  先说优点:
  1.数据库中表格可以直接作为数据源帮顶到列表控件(WP7 SQL CE虽然能作为数据源,但是数据源如果有增删的操作,那么列表控件是反应不出来的)
  2.如果表的结构发生改变你不用担心兼容性的问题(有一点需要注意,就是类型的改变需要考虑下的,比如原来是简单类型的,后来改成复杂类型了,那么你还是另外加一个属性吧)
  3.表的结构是可以使用复杂类型作为属性的,只要那个复杂类型标记了[DataContract]和[DataMenber]就行。
  缺点:
  1.虽然也支持一个数据库中存在多个表,但是表之间不支持关联。
  2.数据表没有索引和主键,你非要有主键的话可以在往表中添加数据的时候自己加上。
  3.数据量比较大的时候会有性能问题(几万条数据那种)
  4.数据的存储没有加密,不过这个问题其实可以解决的。
  以上提到的缺点,说实话对于一般的数据存储来说其实没什么问题的。除非那些对性能(在数据量小的情况下几乎不会有这个问题)和安全要求较高的就不适合使用这种方法。
  
  以上所提到的方法是我在开发自己的APP中所用的方法,虽然不是完美的解决方案,但是作为应急用搓搓有余了。
  说到底是一个山寨版的数据库,欢迎拍砖!
  源码下载
  
  
  
  
  
  
  
  
  
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-69548-1-1.html 上篇帖子: Windows 8 学习笔记(十五)--.Windows 8 RP Metro 墓碑机制思考 下篇帖子: Windows 8 应用开发权威指南 之 检测方向的传感器(3)确定设备方向
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表