uwp连接mysql数据库_UWP使用Realm数据库

Realm数据库是SQLite、Core Data的替代品,跨平台、支持加密、更快的执行效率,不用写sql。

安装Realm

使用VS新建一个UWP项目,右键解决方案资源管理器中项目节点下的的引用节点,选择管理Nuget程序包,打开NuGet包管理器。切换到浏览标签,搜索Realm,选择第一项Realm,点击右侧的安装。

24b96b496777?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

uwp_realm_01.png

创建 FodyWeavers.xml 文件

在项目中,新建一个xml文件,命名为FodyWeavers.xml,文件属性保持默认,内容如下:

The Realm package contains everything you need to use Realm. It depends on Fodyweaver, responsible for turning your RealmObject subclasses into persisted ones.

目前更新项目之后发现现在的写法要改成下面这样,而且注意NuGet还要同时安装Fody,Realm.Fody。

创建至少一个RealmObject派生类

//User.cs

class User: RealmObject

{

[Realms.PrimaryKey]

public int Id { get; set; }

public string Name { get; set; }

public string Sex { get; set; }

public int Age { get; set; }

}

//Book.cs

class Book : RealmObject

{

[Realms.PrimaryKey]

public int Id { get; set; }

public string Name { get; set; }

}

Realm数据库基本操作

连接或创建数据库

//对Realm数据库进行配置,Test.relam为数据库文件名

var config = new RealmConfiguration("Test.realm");

//打印一下这个数据库文件实际的保存路径

System.Diagnostics.Debug.WriteLine($"{Windows.Storage.ApplicationData.Current.LocalFolder.Path}\\Test.relam");

//设置数据库中的表对应的实体类,这里设置数据库只有一个User表;如果不设置,默认所有派生自RealmObject的类都会在该数据库中生成对应表

config.ObjectClasses = new Type[] { typeof(User) };

//设置数据库加密密码,长度为固定的64 bytes

//config.EncryptionKey = new byte[64]

//{

// 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,

// 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,

// 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,

// 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,

// 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,

// 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,

// 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,

// 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78

//};

//获取Relam实例

var realm = Realm.GetInstance(config);

插入记录

//插入记录

var mandUser = new User() { Id = 3, Name = "Mandarava", Sex = "M", Age = 66 };

realm.Write(() =>

{

realm.Add(new User() { Id = 1, Name = "Tom", Sex = "M", Age = 77 });

realm.Add(new User() { Id = 2, Name = "Jerry", Sex = "F", Age = 88 });

realm.Add(mandUser);

realm.Add(new User() { Id = 4, Name = "Jack", Sex = "M", Age = 99 });

});

更新记录

//更新记录

realm.Write(() => {

//更新mandUser的Sex字段

mandUser.Sex = "男";

//更新mandUser //因为这里的new User的Id=3,mandUser的Id也是3,Id是PrimaryKey,所以这里仍然更新mandUser

realm.Add(new User() { Id = 3, Name = "鳗驼螺", Sex = "Male", Age = 88 }, true);

});

查询记录

//查询记录

var users = realm.All().Where(user => user.Sex == "M");

foreach(var user in users)

{

System.Diagnostics.Debug.WriteLine($"{user.Id}\t{user.Name}\t{user.Sex}\t{user.Age}");

}

删除记录

//删除记录

realm.Write(() =>{

//删除指定的记录

realm.Remove(mandUser);

//删除满足条件的一组记录

var dusers = realm.All().Where(user => user.Sex == "M");

realm.RemoveRange(dusers);

});

注:Realm.Write方法都是基于事务处理的。

一些问题和解决方法

No RealmObjects 错误

如果在运行时出现下面的错误:

System.InvalidOperationException:“No RealmObjects. Has linker stripped them? See https://realm.io/docs/xamarin/latest/#linker-stripped-schema”

如果没有在项目中写任何RelamObject派生类,就会出现这个问题。实际上是config.ObjectClasses没有设置造成的。所以,至少需要创建一个RelamObject的派生类。

非自动属性问题

Realm只支持自动属性,如:

[Realms.PrimaryKey]

public int Id{get;set;}

如果写成下面这种常规属性的形式:

[Realms.PrimaryKey]

public int Id {

get { return id; }

set { id = value; }

}

private int id;

你会得到类似下面的错误:

Fody/RealmWeaver: User.Id has [PrimaryKey] applied, but it's not persisted, so those attributes will be ignored.

当然,你可能会说把[Realms.PrimaryKey]去掉就行了。去掉是不会报错了,但这个属性仍然会被忽略,不会成为Realm数据库表的字段,因为根本问题不在于这个属性修饰符,而是它被视为it's not persisted。

那如果我们在设置属性的时候,确有要求需要做点额外操作(比如检查属性值是否符合要求),这种情况下只能写成非自动属性,比如:

public int Age {

get { return age; }

set { age = value >= 0 ? value : 0; }

}

private int age;

但非自动属性又不能被Realm持久化,那这种情况下该怎么办?

为解决这类问题,RealmObject提供了一个PropertyChanged事件,该事件在属性发生改变时被触发。所以,我们要检查某个属性值是否符合我们的要求,或者在属性设置时干点其它的事,属性仍然写成自动属性,然后可以去监听这个事件,在该事件中去检查属性合法性(或干点别的),如:

//User.cs

class User: RealmObject{

...

public int Age{ get;set; }

}

//App

var mandUser = new User() { Id = 3, Name = "Mandarava", Sex = "M" };

mandUser.PropertyChanged += (obj, evt) =>

{

var usr = obj as User;

switch (evt.PropertyName)

{

case nameof(User.Age): if (usr.Age < 0) usr.Age = 0; break;

default: break;

}

};

mandUser.Age = 66;

当然,你可能有很多个User实例,每个都要添加一个PropertyChanged事件,太麻烦;而且像上面的代码,你需要在监听PropertyChanged事件后,再去设置要监听的属性Age的值,否则就会错过监听。为避免这些麻烦,因为User类派生自RealmObject类,所以更好的做法是直接在User类中重写OnPropertyChanged事件,像这样:

//User.cs

protected override void OnPropertyChanged(string propertyName)

{

base.OnPropertyChanged(propertyName);

switch (propertyName)

{

case nameof(Age): if (Age < 0) Age = 0; break;

default: break;

}

}

当然,还有一种方法是建立二个属性来解决这个问题,其中一个必是自动属性(可以设为private):

private int age { get; set; }

public int Age {

get { return age; }

set { age = value >= 0 ? value : 0; }

}

这样也可以达到目的。当然,这个方法的问题是最终数据库中年龄字段的名称变成了age,如果你说我一定要让字段名是Age,咋整?可以使用MapTo属性修饰符来限定持久化后的属性名称,像这样:

[Realms.MapTo("Age")]

private int age { get; set; }

Cannot modify managed objects outside of a write transaction 错误

从Realm数据库中取出的数据对象,或通过realm.Add已经加入到Realm数据库中的对象,在更新该对象的Realm字段值时,需要使用Realm.Write(Action)方法(或它的异步版方法)来更新。比如,在前文中,mandUser是通过new来创建的,然后它被加入到Realm数据库中,这之后,它就与这个数据库有关联了,要更新它的Realm字段,不能直接像这样:

mandUser.Sex = "男";

这种方式就会导致本错误的出现,必须使用下面的方式来更新:

realm.Write(() => {

mandUser.Sex = "男";

};

Write方法是基于事务的更新,这也是为什么错误信息显示为outside of a write transaction的原因。

那么,普通new出来的对象,与从Realm数据库中加载的数据对象有什么区别呢? 这具体看这个对象的Realm属性值。所有派生自RealmObject的对象,都有Realm属性,如果这个属性值为null,表示这个对象并没有关联Realm数据库,一个对象刚new时,它的Realm属性值为null(你也可以直接用RealmObject.IsManaged来检测,检测结果为true就表示Realm不为null,这也就是出错信息中指出的所谓的managed objects)。这种情况下,如果使用realm.Write(Action)是没效果的(当然,它会改变这个对象的属性值,但与Realm数据库无交互),因为这条记录在realm关联的数据库中并不存在,需要先使用realm.Add方法来将它添加到数据库中,一旦添加后,这个对象的Realm属性值不再为null(事实上,它的实际值就是realm),已经与Realm数据库进行了关联(从Realm数据库中加载到的数据也一样),需要使用realm.Write(Action)来更新其Realm字段数据。

这里,realm和mandUser.Realm在这个示例中是同一个对象,我们可以使用realm.IsSameInstance(mandUser.Realm)来对二者进行检测是否相同,如果检测结果为false,那表示这二者不是关联的同一数据库,不能使用realm来更新mandUser,当然,你可以用mandUser.Realm.Write(Action)来更新它自己,但注意mandUser.Realm可能为null,如果它尚未关联Realm数据库。

如果想通过一个对象来更新一条已有记录,这里有一个方法Realm.Add(RealmObject, bool)。这个方法的主要功能显然是用来向数据库添加记录的,不过它的第二参数是表示如果记录已经存在是否更新它,这个方法的第一参数是一个RealmObject对象,这个对象并不要求它已经关联了数据库,也就是它的Realm属性值可以是null,这个时候,如果要用它去更新数据库中已有的记录,就要设置这个对象的标记为[Realms.PrimaryKey]属性的Realm字段,让这个字段的值与数据中的要更新的记录中的该字段值保持一致,这样在更新的时候(二参为true),就会在数据库中找到并更新该条记录,如前文的示例:

realm.Write(() => {

mandUser.Sex = "男";

//更新mandUser //因为这里的new User的Id=3,mandUser的Id也是3,Id是PrimaryKey,所以这里仍然更新mandUser

realm.Add(new User() { Id = 3, Name = "鳗驼螺", Sex = "Male", Age = 88 }, true);

});

Relam数据库管理工具

可以使用 Realm Studio 管理数据库文件,它是官方提供的一个跨平台Realm数据库管理工具。

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值