Windows Phone 7 使用本地数据库
openkk
13年前
<p>终于在Wp7.1中加入了数据库,使保存、查找、插入数据不再痛苦。在WP7中如果要做到这些,要么使用XML自已实现,要么使用第三方数据库,但是第三方数据库要么性能不好,要么占用空间太大,要么收费,现在总算有原生的本地数据库了。</p> <p>1. 架构</p> <p><img alt="Windows Phone 7 使用本地数据库" src="https://simg.open-open.com/show/55464d93fd6ee915542d6f889121a090.png" width="600" height="200" /></p> <p>这个本地数据库,不能直接支持Transact-SQL,需要通过LINQ to SQL 对象模型作为Proxy来操作数据库,为此引入了一个新的类System.Data.Linq.DataContext。这与windows mobile上的SQL CE有了很大的差别。</p> <p> </p> <p>2. LINQ to SQL</p> <p>在Windows phone中,LINQ to SQL既不能直接支持执行Data Definition Language(DDL)也不支持Data Modeling Language(DML),另外也不能直接访问ADO.NET。只能支持Microsoft SQL Server Compact Edition (SQL CE)的数据类型。并且需要通过DataContext方式来操来数据库。</p> <p> </p> <p>3. 支持的数据类型</p> <table border="1" cellspacing="0" cellpadding="0"> <tbody> <tr> <td> <p>数据类型</p> </td> <td> <p>描述 </p> </td> </tr> <tr> <td> <p>bigint </p> </td> <td> <p>Integer (whole number) data from –2^63 (–9,223,372,036,854,775,808) through 2^63–1 (9,223,372,036,854,775,807). Storage size is 8 bytes.</p> </td> </tr> <tr> <td> <p>integer </p> </td> <td> <p>Integer (whole number) data from –2^31 (–2,147,483,648) through 2^31–1 (2,147,483,647).</p> <p>Storage size is 4 bytes.</p> </td> </tr> <tr> <td> <p>smallint </p> </td> <td> <p>Integer data from –32,768 to 32,767. Storage size is 2 bytes.</p> </td> </tr> <tr> <td> <p>tinyint </p> </td> <td> <p>Integer data from 0 to 255. Storage size is 1 byte.</p> </td> </tr> <tr> <td> <p>bit </p> </td> <td> <p>Integer data with a value of either 1 or 0.</p> <p>Storage size is 1 bit.</p> </td> </tr> <tr> <td> <p>numeric (p, s) </p> <p>Synonyms: </p> <p>decimal(p,s) and dec (p,s) </p> </td> <td> <p>Fixed-precision and scale-numeric data from –10^38+1 through 10^38–1. The <em>p </em>variable specifies precision and can vary between 1 and 38. The <em>s</em> variable specifies scale and can vary between 0 and <em>p</em>.</p> <p>Storage size is 19 bytes.</p> </td> </tr> <tr> <td> <p>money </p> </td> <td> <p>Monetary data values from (–2^63/10000) (–922,337,203,685,477.5808) through 2^63–1 (922,337,203,685,477.5807), with accuracy to a ten-thousandth of a monetary unit. Storage size is 8 bytes.</p> </td> </tr> <tr> <td> <p>float </p> </td> <td> <p>Floating point number data from –1.79E +308 through 1.79E+308</p> <p>Storage size is 8 bytes.</p> </td> </tr> <tr> <td> <p>real </p> </td> <td> <p>Floating precision number data from –3.40E+38 through 3.40E+38.</p> <p>Storage size is 4 bytes.</p> </td> </tr> <tr> <td> <p>datetime </p> </td> <td> <p>Date and time data from January 1, 1753, to December 31, 9999, with an accuracy of one three-hundredth second, or 3.33 milliseconds. Values are rounded to increments of .000, .003, or .007 milliseconds.</p> <p>Stored as two 4-byte integers. The first 4 bytes store the number of days before or after the <em>base date</em>, January 1, 1900. The base date is the system's reference date. Values for datetime earlier than January 1, 1753, are not permitted. The other 4 bytes store the time of day represented as the number of milliseconds after midnight. Seconds have a valid range of 0–59.</p> <p>Format Example </p> <p><em>yyyy/mm/dd hh:mm:ss</em> 1947/08/15 03:33:20 </p> <p><em>mm/dd/yyyy hh:mm:ss</em> 04/15/1947 03:33:20 </p> <p><em>dd mmm yyyy hh:mm:ss</em> 15 Jan 1947 03:33:20 </p> <p><em>dd mmmm yyyy h:mm:ss</em> 15 January 1947 03:33:20 </p> </td> </tr> <tr> <td> <p>national character(n) </p> <p>Synonym:nchar(n) </p> </td> <td> <p>Fixed-length Unicode data with a maximum length of 4000 characters. Default length = 1. Storage size, in bytes, is two times the number of characters entered.</p> </td> </tr> <tr> <td> <p>national character varying(n) </p> <p>Synonym:nvarchar(n) </p> </td> <td> <p>Variable-length Unicode data with a length of 1 to 4000 characters. Default length = 1. Storage size, in bytes, is two times the number of characters entered.</p> </td> </tr> <tr> <td> <p>ntext⊃1; </p> </td> <td> <p>Variable-length Unicode data with a maximum length of (2^30–2)/2 (536,870,911) characters. Storage size, in bytes, is two times the number of characters entered.</p> <p><strong>Note</strong> </p> <p>ntext is no longer supported in string functions. </p> </td> </tr> <tr> <td> <p>nchar </p> </td> <td> <p>Fixed-length Unicode character data of n characters. n must be a value from 1 through 4,000. The storage size is two times n bytes.</p> </td> </tr> <tr> <td> <p>binary(n) </p> </td> <td> <p>Fixed-length binary data with a maximum length of 8000 bytes. Default length = 1.</p> <p>Storage size is fixed, which is the length in bytes declared in the type.</p> </td> </tr> <tr> <td> <p>varbinary(n) </p> </td> <td> <p>Variable-length binary data with a maximum length of 8000 bytes. Default length = 1.</p> <p>Storage size varies. It is the length of the value in bytes.</p> </td> </tr> <tr> <td> <p>image⊃1; </p> </td> <td> <p>Variable-length binary data with a maximum length of 2^30–1 (1,073,741,823) bytes.</p> <p>Storage is the length of the value in bytes.</p> </td> </tr> <tr> <td> <p>uniqueidentifier </p> </td> <td> <p>A globally unique identifier (GUID). Storage size is 16 bytes.</p> </td> </tr> <tr> <td> <p>IDENTITY [(s, i)] </p> </td> <td> <p>This is a property of a data column, not a distinct data type.</p> <p>Only data columns of the integer data types can be used for identity columns. A table can have only one identity column. A seed and increment can be specified and the column cannot be updated.</p> <p>s (seed) = starting value</p> <p>i(increment) = increment value</p> </td> </tr> <tr> <td> <p>ROWGUIDCOL </p> </td> <td> <p>This is a property of a data column, not a distinct data type. It is a column in a table that is defined by using the uniqueidentifier data type. A table can have only one ROWGUIDCOL column.</p> </td> </tr> <tr> <td> <p>Timestamp/rowversion </p> </td> <td> <p>This is an automatically generated unique binary number.</p> <p>Storage size is 8 bytes.</p> </td> </tr> </tbody> </table> <p>⊃1;在SQL Server Compact 4.0中,当Ntext 和 image 数据超过256 bytes 时将会保存到一个新的数据页。这会影响到数据库的密度,因为SQL Server Compact 4.0 数据库是按页方式面不是按字节方式来压缩的。</p> <p>4. 创建工程</p> <p>新建一个Windows Phone工程,最好是MVVM工程,也就是选择新建工程中的Windows Phone Databound Application 模板直接生成或者手工创建MVVM工程。创建好后,将System.Data.Linq命名空间引入到工程。这个命名空间所在位置\Program Files\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0\Profile\WindowsPhone71中。</p> <p>5. 创建数据库</p> <p>新建一个类继承System.Data.Linq.DataContext类,这样就可以用这个类来控制数据库了。</p> <pre class="brush:xml; toolbar: true; auto-links: false;">public class MyDataContext : DataContext { public const string ConnectionStr = "Data Source=isostore:/MyDB.sdf"; public Table <mytable> Rows; public MyDataContext() : base(ConnectionStr) { } } </mytable></pre> <p></p> <p>在这个类中同时创建数据库表类。</p> <pre class="brush:xml; toolbar: true; auto-links: false;">[Table] public class MyTable : INotifyPropertyChanged, INotifyPropertyChanging { private int _index; [Column(IsPrimaryKey = true, CanBeNull = false, IsDbGenerated = true, DbType = "INT NOT NULL Identity", AutoSync=AutoSync.OnInsert)] public int Index { get { return _index; } set { if (_index != value) { NotifyPropertyChanging("Index"); _index = value; NotifyPropertyChanged("Index"); } } } private string _name; [Column] public string Name { get { return _name; } set { NotifyPropertyChanging("Name"); _name = value; NotifyPropertyChanged("Name"); } } private String _gen; [Column] public String Gen { get { return _gen; } set { NotifyPropertyChanging("Gen"); _gen = value; NotifyPropertyChanged("Gen"); } } private int _age; [Column] public int Age { get { return _age; } set { NotifyPropertyChanging("Age"); _age = value; NotifyPropertyChanged("Age"); } } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } #endregion #region INotifyPropertyChanging Members public event PropertyChangingEventHandler PropertyChanging; private void NotifyPropertyChanging(string propertyName) { if (PropertyChanging != null) { PropertyChanging(this, new PropertyChangingEventArgs(propertyName)); } } #endregion }</pre> <p></p> <p>6. 操作数据库</p> <p>新建一个ViewModel类,在这个类中实现数据库的操作。在这个类中实现了对数据的选择、保存、更新和删除。在对数据库的操作因为不能直接使用Transact_SQL,所以操作都是通过LINQ来完成的。</p> <pre class="brush:xml; toolbar: true; auto-links: false;">MyDataContext _DB; public void SelectData() { if (IsAddedToDB) { if (_DB.DatabaseExists()) { IEnumerator <mytable> enumerator = _DB.Rows.GetEnumerator(); while (enumerator.MoveNext()) { this.Items.Add(enumerator.Current); } IsAddedToDB = false; } } } public bool SaveData(MyTable table) { try { this.Items.Add(table); _DB.Rows.InsertOnSubmit(table); _DB.SubmitChanges(); } catch (Exception e) { return false; } return true; } public bool DeleteData(MyTable table) { try { if (_DB.DatabaseExists()) { _DB.Rows.DeleteOnSubmit(table); _DB.SubmitChanges(); this.Items.Remove(table); } } catch (Exception e) { return false; } return true; } public bool UpdateData(MyTable source, MyTable dest) { try { var tables = from item in this.Items where (int)item.Index == source.Index select item; foreach (MyTable mt in tables) { mt.Name = dest.Name; mt.Age = dest.Age; mt.Gen = dest.Gen; break; } MyTable table = _DB.Rows.GetOriginalEntityState(source); table.Name = dest.Name; table.Age = dest.Age; table.Gen = dest.Gen; _DB.SubmitChanges(); } catch (Exception e) { return false; } return true; } </mytable></pre> <p></p> <p>以下是运行效果:</p> <p><img alt="Windows Phone 7 使用本地数据库" src="https://simg.open-open.com/show/2c619014661640367e9439e2fc3b2d58.png" width="366" height="685" /></p> <p><img alt="Windows Phone 7 使用本地数据库" src="https://simg.open-open.com/show/bc1d4f147538a1a1cd91c5f9f4ec4e61.png" width="364" height="690" /></p> <p><img alt="Windows Phone 7 使用本地数据库" src="https://simg.open-open.com/show/65d20252883b43a2843ba3fd903fa38c.png" width="365" height="687" /></p> <p><img alt="Windows Phone 7 使用本地数据库" src="https://simg.open-open.com/show/46c74cc8fb7b8b2cb505c54b32f35410.png" width="368" height="699" /></p>