Sterling資料庫是一個NoSQL 物件導向的資料庫產品,不僅可用於Silverlight for Desktop而且可用於Windows Phone上。最近在一個Windows Phone項目上選擇了Sterling作為資料庫,主要原因有二:1.支援Linq查詢 2.功能全面
使用Sterling進行資料存取操作,可參考其User Guide, 在實際項目遇到了一些問題,幾個注意事項如下:
1. 索引欄位的值不能為null,否則儲存時會遇到異常。這一點在User Guide中 Index一節中沒有提到,CodePlex上的disussion中提到了一個解決方案:在Index定義時指定預設值。例如如下index_GroceryItem_Rating的定義
protected override System.Collections.Generic.List<ITableDefinition> _RegisterTables() { return new List<ITableDefinition> { CreateTableDefinition<Tombstone,bool>(c=>true), CreateTableDefinition<Grocery,int>(g=> g.Id), CreateTableDefinition<GroceryItem,int>(x=> x.Id)
.WithIndex<GroceryItem,int,int>(index_GroceryItem_GroceryId, x=> x.GroceryId)
.WithIndex<GroceryItem,string,int>(index_GroceryItem_Rating, x=> x.Rating??
string.Empty)
//index cannot be null, so set default value if null
.WithIndex<GroceryItem,int,int>(index_GroceryItem_Quantity, x=> x.Quantity) }; }
2. Save之後使用Flush,以免程式異常終止後導致資料庫主鍵及索引的破壞 參見 User Guide 之 Save
3. Auto Identity - 實現自增主鍵,需要實現一個trigger
public class GroceryTrigger : BaseSterlingTrigger<Grocery, int> { private int _nextId; public GroceryTrigger(int nextId) { _nextId = nextId; } public override bool BeforeSave(Grocery instance) { if (instance.Id < 1) { instance.Id = _nextId++; } return true; } public override void AfterSave(Grocery instance) { return; } public override bool BeforeDelete(int key) { return true; } }
並在程式啟動或啟用時(Application_Launching與Application_Activated事件中)初始化
private void ActivateEngine() { _engine = new SterlingEngine(); _logger = new SterlingDefaultLogger(SterlingLogLevel.Information); _engine.Activate(); _database = _engine.SterlingDatabase.RegisterDatabase<GroceryDatabase>(); int maxGroceryListId = _database.Query<Grocery, int>().Any() ? (from id in _database.Query<Grocery, int>() select id.Key).Max() + 1 : 1; _database.RegisterTrigger<Grocery, int>(new GroceryDatabase.GroceryTrigger(maxGroceryListId)); }
4. Caching的副作用。如果使用Query語句而不是Load語句獲得對象,則獲得對象是Cache的版本而不是資料庫儲存的版本,如果對Cache版本的修改還未通過Save操作提交,則Cache版本與資料庫儲存的版本是不一致的。不注意這一點可能會遇到一些意想不到的Bug。例如在一個page的view model使用如下Query語句載入了資料:
var items = (from item in App.Database.Query<GroceryItem, int, int>(GroceryDatabase.index_GroceryItem_GroceryId) where item.Index == groceryId select item).ToList();
使用者通過UI操作,修改了某些資料的值。page中有一個Save按鈕和Cancel按鈕,如果使用者不想儲存,選擇取消,則對資料的修改沒有提交。但是這時候Cache中的值已經改變。如果使用者重新進入此page,再執行上面的Query語句,則得到的是Cache中的版本,這就與預期不符了。
解決方案是通過Load語句載入資料,保證每次載入的都是資料庫中的版本:
var itemIds = (from x in App.Database.Query<GroceryItem, int, int>(GroceryDatabase.index_GroceryItem_GroceryId) where x.Index == groceryId select x.LazyValue.Value.Id).ToList(); foreach (int id in itemIds) { var item = App.Database.Load<GroceryItem>(id); Items.Add(item); }