[备注]本系列文章中的案例程序调试环境包括:
1. Windows 7;
2. .NET 4.0;
3. Visual Studio 2010;
4. Windows Phone Developer Tools RTW;
5. Sqlite Client for Windows Phone ( http://sqlitewindowsphone.codeplex.com/);
6. (推荐) sqlite-manager ( http://code.google.com/p/sqlite-manager/);
7. (推荐) MVVM Light Toolkit ( http://mvvmlight.codeplex.com/).
一、Sqlite Client for Windows Phone简介
大家都知道,SQLite是一个著名的开源的嵌入式的数据库系统,目前已经提供对于iOS和Android的良好支持。在此,应当让我们感谢Dan Ciprian Ardelean,是他带给我们WP7版本的SQLite-C#-SQLite!最近几个月,作者对早期的版本又进行了更新,得到一个功能更强大和更容易使用的解决方案,改名为Sqlite Client for Windows Phone,在知名的开源网站CodePlex上发布,网址是 http://sqlitewindowsphone.codeplex.com/releases。
▲图1. 下载Sqlite Client for Windows Phone的界面截图
Sqlite Client for Windows Phone进行大范围的更新,如提供对于布尔类型、大型数据(Blobs)以及事务的全面支持,此外,下载包中还一并提供了一个全面的示例,供开发者学习之用。
+O])}p<
K zq%h;{ ▲图2. Sqlite Client for Windows Phone源码工程及示例工程架构
[;<(`P`J
qj8&?v}S 接下来的操作就很简单了:重新构建源码工程,得到一个程序集Community.CsharpSqlite.WP.dll(Release版本大小是525 KB)。然后,在你的WP7 Silverlight 项目中添加对该程序集的引用。最后,你便可以使用Sqlite Client for Windows Phone提供的本地数据库支持功能了。
TsuqbJcC 二、Sqlite Client for Windows Phone基础类库剖析
r@K03Y . 如果您以前有过任何基于SQL脚本的数据库编程经验,那么您可以轻松地使用Sqlite Client for Windows Phone功能。特别值得一提的是,此工程建基于以前的C#-SQLite项目之一,通过引入几个帮助器类(在文件SQLiteClient.cs),即SQLiteException、SQLiteConnection和SQLiteCommand,进一步简化了基本的数据库和表相关操作。接下来的几幅图展示了Sqlite Client for Windows Phone中提供的主要组件及其之间的关联关系。
jGNJNO3
M(YO[8^[6 ▲图3. Sqlite Client for Windows Phone最顶层组件
(h*3[5i
K]7T-#]GI ▲图4. SQLiteConnection类中的主要组件
n5 ]<+6
ZY:do)bk ▲图5. SQLiteCommand类中的主要组件
>=1x~X 怎么样!如果您以前熟悉任何基于SQL的数据库开发,相信上面的这些组件对您会非常亲切吧。
tgV%sk 先别急,在正式使用Sqlite Client for Windows Phone之前,有必要再向您介绍另外一个非常有用的工具,名为sqlite-manager ( http://code.google.com/p/sqlite-manager/)。这个工具是以FireFox插件的方式提供的。到现在您应该明白了,绝大多数与SQLite数据库相关的操作,例如创建SQLite数据库、表、视图、索引等等,都可以通过sqlite-manager轻松完成。
7#J2:~!Y
`s&CL6A 1.使用SQLite Manager简化数据库管理
> <5^zx;m 如前所述,SQLite Manager是一个Firefox插件,使用Firefox的加载项管理器你可以很容易地获取和安装这个控件(图6)。
;o@+ Us{
I}k*4z,1| ▲图6. 使用Firefox的加载项管理器获取和安装SQLite Manager插件
Z VIui$ 如图所示,如果你打开Firefox的插件管理器,然后输入“SQLite Manager”搜索文本,你会很容易检索到此加载项。然后,您可以点击按钮“添加到Firefox... ”开始下载并安装SQLite Manager。请注意,在Firefox的提示后,你应该重新启动Firefox以完成安装。
X%PL uWS 使用SQLite Manager是容易的。说实在的,这是我第一次使用SQLite Manager,我发现这个工具功能强大而且极易上手。如果您使用过VB6中,你可能熟悉其中内置的数据库管理工具-VisData(以便以内置方式创建小型的Access数据库)。说实话,VisData确实是不容易使用,但在当时我们觉得已经相当不错了。现在,你只须记住,SQLite Manager的功能要比VisData强大1000倍。下图展示了SQLite Manager的一个使用快照。
WyR/:^
#Du={- ▲图7. SQLite Manager使用快照
<d]QZVrb* 从图中可见,你可以使用SQLite Manager来实现几种各种SQLite相关操作。请注意,要想了解更多的有关于SQLite的概念及详细使用语法,请从这款插件的帮助菜单中寻找答案。
{t8>AgO 另外,你也会注意到,在本文简单的示例工程中,我仅创建了一个表格Customer,对应的数据库文件为database1.sqlite(如图8所示)。
Am.4rQu4
CFsg+d ▲图8. 使用SQLite Manager定义表格Customer字段
z@3_{^L8v 在创建完数据库database1.sqlite后,关闭SQLite Manager插件。然后,把此文件复制或移动到对应示例工程WP7SQLiteClient的根目录下。请注意,接下来,把它的Build Action属性设置为Resource模式。设置成这种模式的原因与接下来的操作方式相关。如果选择Content模式,则在后台的示例工程中你需要修改对应的部分源码。
&Sax,N&B
q t>b te* 2.一个有用的工具类-DBHelper
)K)cES%/6 如上所述,Sqlite Client for Windows Phone使用众所周知的SQL操作针对典型的数据库操作提供了一个高层次的封装。因此,在Silverlight for Windows Phone 7编程中为了处理SQLite数据库操作,我们可以直接使用在文件SQLiteClient.cs中定义的对象(在源库项目),即SQLiteException、SQLiteConnection和SQLiteCommand等。
.BWbe n; 虽然Sqlite Client for Windows Phone并没有提供与独立存储的直接互动,但显然增加对独立存储支持是必要的,这样可以改善系统的性能。因此,我们可以进一步封装前面提到的SQLiteClient对象。为此,Chris开发了一个非常好用的实用工具类,叫做DBHelper。为了应用于我们自己的示例,我对它做了轻微的修改。完整的源码如下。
LElm5 列表1:更新版本的工具类DBHelper
@1!0*}8iMJ //others omitted…
6l5:0ZiN
<v08#sIQ" using SQLiteClient;
7z!q6.X
fb okDxx>E using System.Linq;
cTcI#b6Q{~
j,S^x7w@a using System.IO.IsolatedStorage;
l'j80L*
b^3/hR G< using System.Collections.Generic;
\UaGqp
7T`.K/ o, using System.Collections.ObjectModel;
H]DQ]R%BJ
xf^{AkN, namespace WP7SQLiteClient.Helpers
[w\.4vL
K`8H*}L {
}|UL}8:K
& ~]+FY public class DBHelper
>/V3FR
lr#NN[5 {
-DYj j1{
Wm>]W ?" private String _dbName;
Rpdm:[4ft
E?wGNW private SQLiteConnection db = null;
O oe#["2t
{0aVj3i public DBHelper(String assemblyName, String dbName)
]y=)pKO
rNZOfBzHW {
&M+m Vs}
:L_OWf : IsolatedStorageFile store =IsolatedStorageFile.GetUserStoreForApplication();
Qf zJ q
DY\'bw y if (!store.FileExists(dbName))
VK QMHs&U
&1~&OMj5 {
6zVWc9U%
]5/4I`a. CopyFromContentToStorage(assemblyName, dbName);
fEvO{Z
zO`PhT"- }
+#,,])P G
8Gc!PO _dbName = dbName;
l8BBHC a
,5)=- (x0 }
icSsiHRL{
~2u |2% ~DBHelper()
xKA=
_, p `@X {
6OLk#C)m
:k^,.M% Close();
EYi\A
f 0zFGebI }
HZ;Q|OM
hn2 XV|MWh private void Open()
y ~"6],B
6*[C&A->F {
?_(1zw&
`I+S:z!. if (db == null)
Dl3J#]]rV
|>yIW`%^4 {
2B>G;nh
8@=PqN^4O db = new SQLiteConnection(_dbName);
:4SqAX;`'
O#UWtv db.Open();
+mMwH{9{O
ebDQrAKc4 }
f^ pTS
M-CZ0E0,"1 }
k*|*~fc/
TF2jB?4,L0 private void Close()
t*Cy'\`
"EFV Z {
kseru61
~YgK2iq/l if (db != null)
QuHf Blzl
j ] 7Ir{ {
"v}1$ {v%
gL 2"3Ri db.Dispose();
{(k| $>
DW7_'Uy db = null;
+q5?f~#
<df60+eo, }
7+Cf&tU
7&ynDu }
wp.0u.j2@
O Rlvcocv //Insert operation
v9tKIFt"
%-$:$ ^h5 public int Insert(T obj, string statement) where T : new()
w] R.k\
1HR,> {
+3o LB
cMF>}o try
rDQ2)#L
0( ksw!aJ {
9pm|/"
:e<N4H0 Open();
E e-^dy%
$,Xl-#bz SQLiteCommand cmd = db.CreateCommand(statement);
;</6 #
)xZ=VZ@b8 int rec = cmd.ExecuteNonQuery(obj);
J[k|#;0
i; vk0 return rec;
l4`4rj^
'eTVV:s }
,i/pUY/
s B~1l catch (SQLiteException ex)
=|H~B}fRp
MFh9Rr\G= {
}s?]-
cw%TW05 System.Diagnostics.Debug.WriteLine("Insert failed: " + ex.Message);
O@YLuTf
OC`(jN2s throw ex;
k#aZ9`]$
I;F)b]; }
3*-FvM>
c\R#FJb ' }
Z ^/
v'?k"-+q // Delete operation
dF)j V
Tjhd02tfJu public void Delete(string statement) where T : new()
p<8F}XR|E
g,8wP.s {
WB]F#g@Pzm
/' [\xA try
5G7|SmT\V
zCL/(pOt {
` 9N8z: @
jaC* O0V&
NlVnf@K3 Open();
C?ai}S
Nro_Cq+ SQLiteCommand cmd = db.CreateCommand(statement);
48%0(,Lk
n7|Hv$ cmd.ExecuteNonQuery();
JN0{T7#M)>
7xFk;5FY }
y6G c0p
7) j(r. catch (SQLiteException ex)
uHSNg)U
0VSqf*{c {
mU'"X 5
'@[r]M_ System.Diagnostics.Debug.WriteLine("Deletion failed: " + ex.Message);
k0 mIp&A
53X>D_H 9 throw ex;
Z>%:FL.9SL
\4"BI@~ }
>x|2
{GnNt'\ }
3U6#un:vhh
%hO}*sXX //Query operation
"`>;thF<
{m 0I0S' public List SelectList(String statement) where T : new()
<!QKY$p>]
COE;b@ {
[Pi~{O`
YeE* Open();
dWmbPOp
aNr,[ SQLiteCommand cmd = db.CreateCommand(statement);
g$HwJ:"p}
!9+t1Y*4 var lst = cmd.ExecuteQuery();
"V?8|<'
~$+;or8 return lst.ToList();
QKvDZ0 t
(gbCnwx }
1 L? JA
ZpJlj_BE public ObservableCollection SelectObservableCollection(String statement)
Vesv_P
B#Gs}/J where T : new()
I=Lx0vF
=(A+W% {
9y_ \7
-37e " List lst = SelectList(statement);
=75@(!S7y:
Ah&DH}jHY ObservableCollection oc = new ObservableCollection();
f B;rf13
HV a&+YI foreach (T item in lst)
WCWCl1{m
E%VJyVu {
B`jQ\_&P0
lo19-TB oc.Add(item);
U;$ _Lq
s Q'zf{[ }
91f=\T-`hY
'"<Fj^jf return oc;
IC? E!5
Kaw Gnok- }
o!^|J"
ylx '_P[U private void CopyFromContentToStorage(String assemblyName,String dbName)
NKt N0@8
kR;1u*P {
J`-OEdlF
\5@7?AZ* IsolatedStorageFile store =
rU'f8<
D$& IsolatedStorageFile.GetUserStoreForApplication();
=h !=HX
?mp8- System.IO.Stream src =
U %3"=xh
".TVCG I_/ Application.GetResourceStream(
H_ d/q}I
]By{V&N+ new Uri("/" + assemblyName + ";component/" + dbName,
=A?S_hvg|
j#BN-m& UriKind.Relative)).Stream;
'QiR5| QN
FMR8bmG IsolatedStorageFileStream dest =
PFi`l
F`e$,3 new IsolatedStorageFileStream(dbName,
)e`+7:
I\MG+yk System.IO.FileMode.OpenOrCreate,
KFv@k/
tl-xChI#n System.IO.FileAccess.Write, store);
<2sdrvgX
*~VGkms src.Position = 0;
'KaGN7LJX/
|9^3]R/b} CopyStream(src, dest);
s$5<{
~U}qMYD dest.Flush();
;=KkIbF
8!Cjq dest.Close();
<T{Uba,WJ
oF,XR( src.Close();
0@2}sZHMR
4"PMf+r dest.Dispose();
t>8k
_V09/g3= }
}C CkIh8o
~oo>7g private static void CopyStream(System.IO.Stream input,
B4yt^
9z(6jv!T{a IsolatedStorageFileStream output)
"dQB7"~
h 2<)\"I {
|pjTznv?
!L e+x9V byte[] buffer = new byte[32768];
Gk3Kvfbw-
sE33R long TempPos = input.Position;
lfPs8V|(k
8x[y5T int readCount;
ReRs Xf]=
}_uN~ Lm do
1jM@hK
C.qhS: {
F *bT9
"8`-g` ;M readCount = input.Read(buffer, 0, buffer.Length);
t{tS%y8kP
2zDs*1nzp if (readCount > 0)
K4a_^bgjS
[3Y/nuMQy {
lL]q;ca~
p38Q 6[ output.Write(buffer, 0, readCount);
q K+ \JGr
:^QlIF5B+ }
[m:IL3k d6
4.O~L%; } while (readCount > 0);
R;OBbz@
`$~q&GA input.Position = TempPos;
8_a* PK
a~eH/8 }
:i&A"
xB~u-G]M7 }
o@-.VK@->
m%S^Jj} }
}5uJ aWtD
xyHtzgE 顺便说一句,对于上面这个帮助类我也没有提供细致的优化编码。希望读者根据您的相关工作能够继续进行这项工作(例如提供更好的泛型化的CRUD支持)并分享给广大网友。简言之,我主要是增加了插入和删除方法。上面的代码中最引起您注意是地方一定是方法CopyFromContentToStorage,正是借助这个方法我们实现了上述目标-建立起SQLite数据库与独立存储的关系。
:l+{@ :[ 三、小结
g${-EaFcG 本文中简要介绍了Sqlite Client for Windows Phone的主要功能及相关的辅助开发工具。在接下来的第二篇文章中,我们将具体构建一个简单的Windows Phone 7客户端应用程序,当然要涉及到Sqlite Client for Windows Phone的基本编程技巧。