代码改变世界

Silverlight本地数据库解决方案之使用Sterling数据库

2011-10-18 11:52  zhoujie  阅读(2042)  评论(2编辑  收藏  举报

Sterling数据库是一个NoSQL数据库,支持linq,是一个Codeplex上的开源项目:http://sterling.codeplex.com

可以为.Net, Silverlight 和 Windows Phone提供本地存储方案,由Jeremy Likeness开发。它使用Isolated Storage存储数据。详情可参考这里 here.

我正在编写一个可以同时运行于windows和mac上的OOB的Silverlight应用程序。我选择了Sterling而不是SQL Server,因为只有用户安装了Silverlight插件,Sterling就可以工作,只需要引用Wintellect.Sterling.dll。

本文通过一个简单的示例演示如何从Sterling数据库保存、获取和删除数据. 此示例类似于购物车的逻辑。

首先创建数据库,Sterling中数据库其实只是一个继承于BaseDatabaseInstance的一个Class。

然后,我们定义数据表。数据表也是一些Class,这里我们定义了4个表。对象导向的数据库,表等同于类,表的字段等同于类的属性。

Sterling1.gif

下面是我们使用的数据库DemoDB的定义:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Wintellect.Sterling.Database;
using System.Collections.Generic;
using SterlingDemoProject.Tables;

namespace SterlingDemoProject.Database
{
    
public class DemoDB : BaseDatabaseInstance
    {
        
public override string Name
        {
            
get { return "Purchase Database"; }
        }
        
protected override System.Collections.Generic.List<ITableDefinition> _RegisterTables()
        {
            
return new List<ITableDefinition>
            {                           
                     CreateTableDefinition<
Customer,int>(c=>c.CustomerID),
                     CreateTableDefinition<
Order,int>(c=>c.OrderID),
                     CreateTableDefinition<
OrderDetails,int>(c=>c.OrderDetailsID),
                     CreateTableDefinition<
Product,int>(c=>c.ProductID)
            };
        }
    }
}

 

CreateTableDefinition是BaseDataInstance类的一个方法,用于创建表定义,其中范型第一个参数定义表,第二个范型参数定义表中键的类型。唯一的参数定义Lamda表达式返回表中键是哪一个属性。

 

Sterling数据库由SterlingEngine管理. 我们定义了 "SterlingService"类包装SterlingEngine来在应用程序的生命周期中提供数据库服务。

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Wintellect.Sterling;
using System.ComponentModel;
using System.Diagnostics;
using SterlingDemoProject.Database;

namespace SterlingDemoProject
{
    
public sealed class SterlingService : IApplicationServiceIApplicationLifetimeAwareIDisposable
    {
        
private SterlingEngine _engine;
        
public static SterlingService Current { getprivate set; }
        
public ISterlingDatabaseInstance Database { getprivate set; }
        
private SterlingDefaultLogger _logger;
        
public void StartService(ApplicationServiceContext context)
        {
            
if (DesignerProperties.IsInDesignToolreturn;
            _engine = 
new SterlingEngine();
            Current = 
this;
        }
        
public void StopService()
        { 
return; }
        
public void Starting()
        {
            
if (DesignerProperties.IsInDesignToolreturn;  
            _engine.Activate();

           Database = _engine.SterlingDatabase.RegisterDatabase<DemoDB>();            
        }
        
public void Started()
        { 
return; }
        
public void Exiting()
        {
            
if (DesignerProperties.IsInDesignToolreturn;
            
if (Debugger.IsAttached && _logger != null)
            {
                _logger.Detach();
            }
        }
        
public void Exited()
        {
            Dispose();
            _engine = 
null;
            
return;
        }
        
public void Dispose()
        {
            
if (_engine != null)
            {
                _engine.Dispose();
            }
            
GC.SuppressFinalize(this);
        }
    }
}

Starting() 方法激活Sterling引擎,然后注册数据库DemoDB。可以创建并注册多个数据库。

 将SterlingService添加到<Application.ApplicationLifetimeObjects>中,应用程序会自动调用该类的。
 

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SterlingDemoProject.App"
xmlns:Sterling="clr-namespace:SterlingDemoProject"
><Application.Resources>

</Application.Resources>
<
Application.ApplicationLifetimeObjects>
<Sterling:SterlingService/>
</Application.ApplicationLifetimeObjects>
</
Application>

下面我们创建View和ViewModel:

第一页包含两个组件,一个ComboBox显示customers列表,一个ListBox显示products列表。选择products和customers,点击place order按钮,可以添加一个订单Order

Sterling2.gif

我们先在数据库中创建一些测试数据。调用DataBase的Save方法可以向数据表中添加数据。

SterlingService.Current.Database.Save(new Customer()
            {
                CustomerID = 1,
                CustomerName = 
"A",
                ShippingAddress = 
"No 9, A road, A Area, A-59"
            });

Sterling3.gif

将Customer对象传进去,Sterling通过反射决定该添加到数据库中的哪一个表中。

由于Sterling没有自动+1的字段,我们只能先通过Query方法查出OrderID的最大值,然后+1。

if((from o inSterlingService.Current.Database.Query<Order, int>() select o.LazyValue.Value).Count() >= 1)
{
                newOrder.OrderID = (from o in SterlingService.Current.Database.Query<Order, int>() select o.LazyValue.Value.OrderID).Max() +
1;
}
            else
{
                newOrder.OrderID = 1;
}
 
SterlingService.Current.Database.Query<Order, int>() 范型参数同Save方法。

我们创建一个 OrderDetailsPage页显示订单详情,下面是ListBox的模板定义:

<ListBox ItemsSource="{Binding CustomerOrderDetails,Mode=TwoWay}" x:Name="lstOrderList" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Row="1" Width="400" Height="500" Grid.Column="1">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="0.9*"/>
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Row="0" Text="{Binding Description}"/>
                        <ListBox Grid.Row="1" ItemsSource="{Binding LstProducts}">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text="{Binding ProductName}" Margin="5"/>
                                        <TextBlock Text="{Binding Price}" Margin="5"/>
                                        <TextBlock Text="{Binding Quantity}" Margin="5"/>
                                        <TextBlock Text="{Binding Amount}" Margin="5"/>
                                        <!--<TextBlock Text="{Binding}" Margin="5"/>-->
                                    </StackPanel>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>
                        <StackPanel Grid.Row="2" Orientation="Horizontal">
                            <TextBlock Text="Total Amount:"/>
                            <TextBlock Text="{Binding TotalAmount}"/>
                        </StackPanel>
                        <Button x:Name="btnDelete" Margin="5" Width="100" Tag="{Binding OrderId}" Content="Order Done" Click="btnDelete_Click" Grid.Column="1" Grid.Row="0" />
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

这个列表框的数据上下文是DisplayOrderDetails的ViewModel:

public class DisplayOrderDetails : INotifyPropertyChanged
    {
 public int OrderId { get; set; }
        public double
TotalAmount { get; set; }
        public string
Description { get; set; }
        List
<Product> _lstProducts;
        public List
<Product> LstProducts
        {
            get
            {
                return
_lstProducts;
            }
            set
            {
                _lstProducts = value;               
                OnPropertyChanged("LstProducts");
            }
        }
        public DateTime
OrderDate { get; set; }
        public int
CustomerID { get; set; }
        public string
CustomerName { get; set; }
}

通过join连接Orders表和Customer表,返回DisplayOrderDetails对象。

CustomerOrderDetails = (from o in SterlingService.Current.Database.Query<Order, int>()
                                    join c in SterlingService.Current.Database.Query<Customer, int>()
                                    on
o.LazyValue.Value.CustomerID equals c.LazyValue.Value.CustomerID                                   
                                    select new DisplayOrderDetails
()
                                    {
                                        Description = o.LazyValue.Value.Description,
                                        OrderDate = o.LazyValue.Value.OrderDate,
                                        OrderId = o.LazyValue.Value.OrderID,
                                        CustomerID = c.LazyValue.Value.CustomerID,
                                        CustomerName = c.LazyValue.Value.CustomerName
                                    }).ToList();

其中LstProducts属性通过连接OrderDetails表和Product表,Linq查询得到。

CustomerOrderDetails.ForEach(c =>
            {              
                c.LstProducts = new List<Product>();
                c.LstProducts = (from od in SterlingService.Current.Database.Query<OrderDetails, int>()
                                 join
p in SterlingService.Current.Database.Query<Product, int>()
                                 on
od.LazyValue.Value.ProductID equals p.LazyValue.Value.ProductID
                                 where
od.LazyValue.Value.OrderID == c.OrderId
                                 select new Product
() {
                                     Price = p.LazyValue.Value.Price,
                                     Quantity = od.LazyValue.Value.Quantity,
                                     ProductID = od.LazyValue.Value.ProductID,
                                     ProductName = p.LazyValue.Value.ProductName                                   
                                 }).ToList();
                c.LstProducts.ForEach(p =>
                c.TotalAmount = c.TotalAmount + (p.Price * p.Quantity));

 

            });


当点击Place Order按钮或者Previous Order按钮时导航到OrderDetailsPage页。

Sterling4.gif

 

 

 OrderDetailsPage显示用户订单详情,点击Order Done按钮执行Delete操作,从数据表中删除。

private void btnDelete_Click(object sender, RoutedEventArgs e)
        {
            Button
btnBox = sender as Button;
            (this.DataContext as OrderVM).DeleteSelectedOrder(int.Parse(btnBox.Tag.ToString()));
        }

public void DeleteSelectedOrder(int orderid)
        {           
            Order
deleteOrder = (from o in SterlingService.Current.Database.Query<Order,int>()
                                 where
o.LazyValue.Value.OrderID == orderid select o.LazyValue.Value).FirstOrDefault();
            if
(deleteOrder != null)
            {
                SterlingService.Current.Database.Delete(deleteOrder);
                SterlingService
.Current.Database.Flush();
            }
            List
<OrderDetails> lstOrderDetails = (from o in SterlingService.Current.Database.Query<OrderDetails, int>() where o.LazyValue.Value.OrderID == orderid select o.LazyValue.Value).ToList();
            lstOrderDetails.ForEach(o =>
                {
                    SterlingService.Current.Database.Delete(o);
                });
 
            GetAllOrderDetails();
        }

同Save方法一样简单,将要删除的Order对象传给Delete方法即可。

结论: Sterling是一个快速,轻量级并且跨平台的Silverlight数据库。

代码下载

 英文原文:http://www.c-sharpcorner.com/UploadFile/kavithakgowd/7496/