【Android】13.3 使用SQLite.NET-PCL访问SQLite数据库
分类:C#、Android、VS2015;
创建日期:2016-02-26
一、简介
本章开头已经说过了,SQLite.NET-PCL用起来很爽,这一节咱们看看怎样使用吧。
二、示例3运行截图
下面左图是单击【初始化表数据】后的结果,右图是单击【获取所有记录】后的结果。
下面左图是单击【添加新行】后的界面,右图是添加后重新获取的所有记录:
修改、删除、查找不再截图了,有兴趣自己玩吧。
三、主要设计步骤
1、添加SQLite.NET-PCL程序包
通过NuGet直接添加即可。
2、创建数据库和表
为了让项目结构看起来更直观,可单独建立一个文件夹(不是必须这样做,仅仅是为了一眼就能看出这个数据库中有哪些表)。比如,在SrcDemos文件夹下添加一个MyDb3Models文件夹,该文件夹用于保存与“MyDb3.db”数据库相关的.cs文件。
(1)添加MyDb3.cs文件
在SrcDemos\MyDb3Models文件夹下添加MyDb3.cs文件:
using SQLite.Net; using SQLite.Net.Platform.XamarinAndroid; using System; using System.IO; namespace MyDemos.SrcDemos.MyDb3Models { public class MyDb3 : SQLiteConnection { /// <summary> /// MyDb3.db的路径 /// </summary> private static string dbPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.Personal), "MyDb3.db"); public MyDb3() : base(new SQLitePlatformAndroid(), dbPath) { CreateTable<Student>(); CreateTable<Course>(); } } }
作为例子,这个帮助器类仅保存了SQlite数据库的路径,实际上还可以用它进一步封装对数据库表的各种操作。
(2)添加Student.cs文件
在SrcDemos\MyDb3Models文件夹下添加该文件。
注意:为了演示不同数据类型的基本用法,这里并没有考虑表结构是否合理,比如同时定义年龄和出生日期实际上是不合适的。
using System; using SQLite.Net.Attributes; namespace MyDemos.SrcDemos.MyDb3Models { [Table("Student")] public class Student { //主键,自动增量 [PrimaryKey,AutoIncrement] public int id { get; set; } //学号 [Unique, NotNull] public string XueHao { get; set; } //姓名 [MaxLength(30), NotNull] public string Name { get; set; } //年龄 public int Age { get; set; } //出生日期 public DateTime BirthDate { get; set; } } }
其中,[Table("…")]特性声明指定该类在数据库中的表名。PrimaryKey特性表示Id为主键,AutoIncrement表示自动增量。
下面是常用的一些特性:
[PrimaryKey] :主键,只能用于int类型的属性。
[AutoIncrement] :自动增量。每插入一条新数据该字段都会自增1,只能用于int类型。
[Column(name)] :对应到表中的字段名,如果不添加该特性,则表中的字段名与属性名相同。
[Table(name)] :表示该类对应到数据库中的表名,如果不加该特性,则数据库中的表名可能会使用该类名的复数形式(MyTable1s)。
[MaxLength(value)] :限制字符串的最大长度。
[Ignore] :表示忽略该属性,即:不在表中生成对应的字段。
[Unique] :表中该列的值不重复。
(3)添加Course.cs文件
在SrcDemos\MyDb3Models文件夹下添加该文件。实际没用它,仅仅是为了演示如何添加多个表。当然了,例子不是实际项目,没必要搞那么复杂,玩玩知道怎么用就行了,也没必要非得和实际项目一致。
using SQLite.Net.Attributes; namespace MyDemos.SrcDemos.MyDb3Models { /// <summary> /// 课程成绩表 /// </summary> [Table("Course")] public class Course { //主键,自动增量 [PrimaryKey,AutoIncrement] public int id { get; set; } //学号 public string StudentId { get; set; } //课程号 public string CourseId { get; set; } //课程名称 public string CourseName { get; set; } //成绩 public int ChengJi { get; set; } } }
3、创建布局页面
布局文件都保存在Resoureces/layout文件夹下。
注意:实际的手机应用程序中一般不要有【返回主页】的按钮,因为它实际上并不是返回,而是新建页。这个例子中包含的【返回主页】仅仅是为了让你看看是如何新建的。另外,实际项目中应该用带返回结果的Intent来实现,为了不搞这么麻烦,例子中并没有这样做。
(1)主页--ch1303_Main.axml文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:text="初始化表数据" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnCreateDB" /> <Button android:text="获取所有记录" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnGetAll" /> <Button android:text="添加新行" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnInsert" /> <Button android:text="修改行" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnUpdate" /> <Button android:text="删除行" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnDelete" /> <Button android:text="通过学号查找行" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnGetDataById" /> <TextView android:id="@+id/txtResult" android:layout_marginTop="20dp" android:text="操作结果" android:minWidth="25px" android:minHeight="25px" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" android:background="@color/myBlue" /> </LinearLayout>
(2)插入页面--ch1303_InsertLayout.axml文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:text="添加新纪录" android:textAppearance="?android:attr/textAppearanceLarge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="30dp" android:layout_gravity="center_horizontal" android:id="@+id/textView1" /> <TextView android:text="学号:" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textViewxuehao" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtNewXueHao" /> <TextView android:text="姓名:" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textView2" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtNewName" /> <TextView android:text="年龄:" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textView3" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtNewAge" /> <Button android:text="添加" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnAddNewRecord" /> <Button android:text="返回主页" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnReturn" /> </LinearLayout>
(3)查找页面--ch1303_SearchLayout.axml文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:text="按学号查找" android:textAppearance="?android:attr/textAppearanceLarge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="30dp" android:layout_gravity="center_horizontal" android:id="@+id/textView1" /> <TextView android:text="学号:" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textView2" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtId" /> <Button android:text="查找" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnSearch" /> <Button android:text="返回主页" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnReturn" /> </LinearLayout>
(4)更新页面--ch1303_UpdateLayout.axml文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:text="修改记录" android:textAppearance="?android:attr/textAppearanceLarge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="30dp" android:layout_gravity="center_horizontal" android:id="@+id/textView1" /> <TextView android:text="学号:" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textView2" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtUpdateId" /> <Button android:text="查找" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnSearch" android:layout_marginBottom="30dp" /> <TextView android:text="姓名" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textView3" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtUpdateName" /> <TextView android:text="年龄" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textView4" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtUpdateAge" /> <Button android:text="更新" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnUpdate" /> <Button android:text="返回主页" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnReturn" /> </LinearLayout>
(5)删除页面--ch1303_RemoveLayout.axml文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:text="删除记录" android:textAppearance="?android:attr/textAppearanceLarge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="30dp" android:layout_gravity="center_horizontal" android:id="@+id/textView1" /> <TextView android:text="学号:" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textView2" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtTaskID" /> <Button android:text="删除" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnDelete" /> <Button android:text="返回主页" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnReturn" /> </LinearLayout>
4、创建Activity
下面的代码将获取数据库的路径并打开该数据库:
using(db = new SQLiteConnection(MyDbHelp.dbPath))
{
……
}
成功打开该数据库之后,剩下的工作只需要利用db就可以轻松完成了。
注意:使用using语句的好处是可确保操作完成后立即关闭数据库连接。
如果不这样做,用SQLiteConnection打开数据库连接后,必须显式调用Close()方法来关闭数据库连接。但是,由于编程人员在项目周期紧张的情况下为了完成任务经常顾头不顾屁股(打开连接操作后常常忘记关闭连接,特别是初学者更是如此),从而导致内存占用越来越多(即所谓的内存泄露),用using语句来实现,可确保不会出现这种情况。
实际上,不管你采用哪种方式操作数据库(包括用内置的API实现),都不要忘了打开数据库连接后,不用时必须立即关闭连接这种要求,否则你就是自己给自己制造了一系列“拌子”说不定啥时候就崴了自己的脚。
(1)插入--ch1303InsertActivity.cs文件
using System; using Android.App; using Android.OS; using Android.Widget; using MyDemos.SrcDemos.MyDb3Models; namespace MyDemos.SrcDemos { [Activity(Label = "【例13-3】SQLite基本用法3")] public class ch1303InsertActivity : Activity { protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.ch1303_InsertLayout); var txtXueHao = FindViewById<EditText>(Resource.Id.txtNewXueHao); var txtName = FindViewById<EditText>(Resource.Id.txtNewName); var txtAge = FindViewById<EditText>(Resource.Id.txtNewAge); Button btnAdd = FindViewById<Button>(Resource.Id.btnAddNewRecord); btnAdd.Click += delegate { string s = "添加成功!"; try { using (MyDb3 db = new MyDb3()) { db.Insert(new Student() { XueHao = txtXueHao.Text, Name = txtName.Text, Age = int.Parse(txtAge.Text), BirthDate = new DateTime(1990, 1, 1) }); } } catch (Exception ex) { s = "添加失败:" + ex.Message; } Toast.MakeText(this, s, ToastLength.Short).Show(); }; FindViewById<Button>(Resource.Id.btnReturn).Click += delegate { StartActivity(typeof(ch1303MainActivity)); }; } } }
(2)删除--ch1303RemoveActivity.cs文件
using Android.App; using Android.OS; using Android.Widget; using MyDemos.SrcDemos.MyDb3Models; namespace MyDemos.SrcDemos { [Activity(Label = "【例13-3】SQLite基本用法3")] public class ch1303RemoveActivity : Activity { protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.ch1303_RemoveLayout); EditText txtId = FindViewById<EditText>(Resource.Id.txtTaskID); Button btnRemove = FindViewById<Button>(Resource.Id.btnDelete); btnRemove.Click += delegate { using (MyDb3 db = new MyDb3()) { var q = db.Table<Student>().Where(t => t.XueHao == txtId.Text); int n = q.Count(); foreach (var v in q) { db.Delete<Student>(v.id); } Toast.MakeText(this, string.Format("删除了 {0} 条记录。", n), ToastLength.Short).Show(); } }; FindViewById<Button>(Resource.Id.btnReturn).Click += delegate { StartActivity(typeof(ch1303MainActivity)); }; } } }
(3)查找--ch1303SearchActivity.cs文件
using Android.App; using Android.OS; using Android.Widget; using MyDemos.SrcDemos.MyDb3Models; namespace MyDemos.SrcDemos { [Activity(Label = "【例13-3】SQLite基本用法3")] public class ch1303SearchActivity : Activity { protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.ch1303_SearchLayout); Button btnSearch = FindViewById<Button>(Resource.Id.btnSearch); btnSearch.Click += delegate { EditText txtId = FindViewById<EditText>(Resource.Id.txtId); using (MyDb3 db = new MyDb3()) { var q = db.Table<Student>().Where(x => x.XueHao == txtId.Text); string s = "未找到学号:" + txtId.Text; if (q.Count() > 0) { Student v = q.First(); s = string.Format("{0} \t{1} \t{2} \t{3:yyyy-MM-dd}", v.XueHao, v.Name, v.Age, v.BirthDate); } Toast.MakeText(this, s, ToastLength.Short).Show(); } }; FindViewById<Button>(Resource.Id.btnReturn).Click += delegate { StartActivity(typeof(ch1303MainActivity)); }; } } }
(4)更新--ch1303UpdateActivity.cs文件
using Android.App; using Android.OS; using Android.Widget; using MyDemos.SrcDemos.MyDb3Models; namespace MyDemos.SrcDemos { [Activity(Label = "【例13-3】SQLite基本用法3")] public class ch1303UpdateActivity : Activity { protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.ch1303_UpdateLayout); EditText txtId = FindViewById<EditText>(Resource.Id.txtUpdateId); EditText txtName = FindViewById<EditText>(Resource.Id.txtUpdateName); EditText txtAge = FindViewById<EditText>(Resource.Id.txtUpdateAge); Button btnSearch = FindViewById<Button>(Resource.Id.btnSearch); btnSearch.Click += delegate { using (MyDb3 db = new MyDb3()) { Student student = db.Table<Student>().Where(x => x.XueHao == txtId.Text).FirstOrDefault(); txtName.Text = student.Name; txtAge.Text = student.Age.ToString(); } }; Button btnUpdate = FindViewById<Button>(Resource.Id.btnUpdate); btnUpdate.Click += delegate { string s = "未找到:" + txtId.Text; using (MyDb3 db = new MyDb3()) { var q = db.Table<Student>().Where(x => x.XueHao == txtId.Text); if (q.Count() > 0) { Student student = q.First(); student.Name = txtName.Text; student.Age = int.Parse(txtAge.Text); db.Update(student); s = "修改成功!"; } } Toast.MakeText(this, s, ToastLength.Short).Show(); }; FindViewById<Button>(Resource.Id.btnReturn).Click += delegate { StartActivity(typeof(ch1303MainActivity)); }; } } }
(5)主页--ch1303MainActivity.cs文件
using System; using Android.App; using Android.OS; using Android.Widget; using MyDemos.SrcDemos.MyDb3Models; namespace MyDemos.SrcDemos { [Activity(Label = "【例13-3】SQLite基本用法3")] public class ch1303MainActivity : Activity { protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.ch1303_Main); var txtResult = FindViewById<TextView>(Resource.Id.txtResult); FindViewById<Button>(Resource.Id.btnCreateDB).Click += delegate { try { using (var db = new MyDb3()) { db.DeleteAll<Student>(); db.Insert(new Student() { XueHao = "01001", Name = "张三", Age = 20, BirthDate = new DateTime(1990, 1, 1) }); db.Insert(new Student() { XueHao = "01002", Name = "李四", Age = 22, BirthDate = new DateTime(1992, 6, 15) }); db.Insert(new Student() { XueHao = "01003", Name = "王五", Age = 21, BirthDate = new DateTime(1993, 12, 8) }); db.DeleteAll<Course>(); db.Insert(new Course() { StudentId = "01001", CourseId = "001", CourseName = "课程1", ChengJi = 90 }); db.Insert(new Course() { StudentId = "01002", CourseId = "001", CourseName = "课程1", ChengJi = 92 }); db.Insert(new Course() { StudentId = "01003", CourseId = "001", CourseName = "课程1", ChengJi = 96 }); txtResult.Text = "初始化完毕!数据库位置:\n" + db.DatabasePath; } } catch (Exception ex) { txtResult.Text = "初始化失败:\n" + ex.Message; } }; FindViewById<Button>(Resource.Id.btnGetAll).Click += delegate { using (var db = new MyDb3()) { var q = db.Table<Student>(); //用法1 //string s = string.Format("Student共有 {0} 条记录:\n", q.Count()); //用法2(C# 6.0提供的增强功能,仅适用于VS2015) string s = $"Student共有 {q.Count()} 条记录:\n"; foreach (var v in q) { s += $"{v.XueHao,10} \t{v.Name,10} \t{v.Age,-10} \t{v.BirthDate:yyyy-MM-dd}\n"; } txtResult.Text = s; } }; FindViewById<Button>(Resource.Id.btnInsert).Click += delegate { StartActivity(typeof(ch1303InsertActivity)); }; FindViewById<Button>(Resource.Id.btnGetDataById).Click += delegate { StartActivity(typeof(ch1303SearchActivity)); }; var btnUpdate = FindViewById<Button>(Resource.Id.btnUpdate); btnUpdate.Click += delegate { StartActivity(typeof(ch1303UpdateActivity)); }; var btnDelete = FindViewById<Button>(Resource.Id.btnDelete); btnDelete.Click += delegate { StartActivity(typeof(ch1303RemoveActivity)); }; } } }