Windows Phone - 使用Sterling数据库几个注意事项『转』

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);
                
            }

 

posted @ 2013-01-17 17:29  NSDefaultRunLoopMode  阅读(167)  评论(0编辑  收藏  举报