作者:webabcd
介绍
Silverlight 4.0 之 WCF RIA Services:DomainService 和 MVVM
在线DEMO
http://www.cnblogs.com/webabcd/archive/2010/08/09/1795417.html
示例
演示如何通过 Domain Service, 以 MVVM 模式实现数据的添加、删除、修改和查询
1、服务端
MyDomainService.cs
* 一个 Domain Service 服务
*/ namespace Silverlight40.Web.Service
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Linq;
using System.ServiceModel.DomainServices.EntityFramework;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
using Silverlight40.Web.Model;
/*
* 用 LinqToEntities 实现 Domain Service 则继承 LinqToSqlDomainService<NorthwindEntities>;用 LinqToSql 实现 Domain Service 则继承 LinqToSqlDomainService<NorthwindEntities>
* Domain Service 内所有对客户端可见的方法都应该是 public 的,Domain Service 内的方法不支持重载
* 对客户端可见的方法要满足命名约定,或为其指定对应的 Attribute。当前支持 6 种数据操作:Query, Update, Insert, Delete, Invoke, Named Update, 详见文档
*
* [EnableClientAccess()] - 该类对客户端可见
* [EnableClientAccess(RequiresSecureEndpoint = true)] - 使用 HTTPS 协议
* [Ignore] - 指定的方法不作为服务而公开
* [Query(IsComposable=true)] - 支持客户端的 linq 查询,而且此查询会被在服务端执行
*
* 在多个 Domain Services 间共享实体:通过 [ExternalReference], [Association()], Context.AddReference() 实现,详见文档
*/
// 服务端的类名为:MyDomainService,则其生成的客户端上下文的类名为:MyDomainContext
[EnableClientAccess()]
public class MyDomainService : LinqToEntitiesDomainService<NorthwindEntities>
{
[Query(IsDefault = true)]
public IQueryable<Category> GetCategories()
{
return this.ObjectContext.Categories;
}
public void InsertCategory(Category category)
{
if ((category.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(category, EntityState.Added);
}
else
{
this.ObjectContext.Categories.AddObject(category);
}
}
public void UpdateCategory(Category currentCategory)
{
this.ObjectContext.Categories.AttachAsModified(currentCategory, this.ChangeSet.GetOriginal(currentCategory));
}
public void DeleteCategory(Category category)
{
if ((category.EntityState == EntityState.Detached))
{
this.ObjectContext.Categories.Attach(category);
}
this.ObjectContext.Categories.DeleteObject(category);
}
[Query(IsDefault
= true)]public IQueryable<Product> GetProducts()
{
return this.ObjectContext.Products;
}
public IQueryable<Product> GetProductsBySort(string sort)
{
return ObjectContext.Products.OrderBy(sort);
}
public void InsertProduct(Product product)
{
if ((product.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(product, EntityState.Added);
}
else
{
this.ObjectContext.Products.AddObject(product);
}
}
public void UpdateProduct(Product currentProduct)
{
this.ObjectContext.Products.AttachAsModified(currentProduct, this.ChangeSet.GetOriginal(currentProduct));
}
public void DeleteProduct(Product product)
{
if ((product.EntityState == EntityState.Detached))
{
this.ObjectContext.Products.Attach(product);
}
this.ObjectContext.Products.DeleteObject(product);
}
public IQueryable<Product> GetProductsByCategoryId(int categoryId)
{
return this.ObjectContext.Products.Where(p => p.CategoryID == categoryId);
}
}
}
MyDomainService.metadata.cs
* [MetadataTypeAttribute()] - 指定类的元数据对象
* [Include] - 生成的客户端上下文包含此字段
* [Exclude] - 生成的客户端上下文不包含此字段
* [Composition] - 指定字段为关联数据,即父实体增删改查时,此关联数据也会做相应的变化。指定此 Attribute 后,需显式指定其为 [Include]
* [Editable(true)], [Editable(false)] - 指定字段是否可编辑
*/ namespace Silverlight40.Web.Model
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
[MetadataTypeAttribute(
typeof(Category.CategoryMetadata))]public partial class Category
{
internal sealed class CategoryMetadata
{
private CategoryMetadata()
{
}
[Key()]
[Display(Name
= "类别名称")] // 显示用public string CategoryName { get; set; }
public string Description { get; set; }
[Exclude]
[Include]
public EntityCollection<Product> Products { get; set; }
}
}
[MetadataTypeAttribute(
typeof(Product.ProductMetadata))]public partial class Product
{
internal sealed class ProductMetadata
{
private ProductMetadata()
{
}
public Category Category { get; set; }
public Nullable<int> CategoryID { get; set; }
public bool Discontinued { get; set; }
public EntityCollection<Order_Detail> Order_Details { get; set; }
[Display(Order
= 0, Name = "产品ID")]public int ProductID { get; set; }
[Display(Order
= 1, Name = "产品名称")]public string ProductName { get; set; }
public string QuantityPerUnit { get; set; }
public Nullable<short> ReorderLevel { get; set; }
public Supplier Supplier { get; set; }
public Nullable<int> SupplierID { get; set; }
public Nullable<decimal> UnitPrice { get; set; }
public Nullable<short> UnitsInStock { get; set; }
public Nullable<short> UnitsOnOrder { get; set; }
}
}
}
2、客户端
ProductViewModel.cs
* 演示:通过 Domain Service, 以 MVVM 模式实现数据的添加、删除、修改和查询
* 此类为 MVVM 中的 ViewModel
*/ 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 Silverlight40.Web.Model;
using System.Collections.ObjectModel;
using Silverlight40.Web.Service;
using System.ComponentModel;
using System.ServiceModel.DomainServices.Client;
using System.Collections.Generic; namespace Silverlight40.WCFRIAServices.DomainServiceAndMVVM
{
public class ProductViewModel
{
public ObservableCollection<Product> Data { get; set; }
private MyDomainContext _context;
public ProductViewModel()
{
Data = new ObservableCollection<Product>();
LoadData();
}
private void LoadData()
{
_context = new MyDomainContext();
EntityQuery
<Product> query = _context.GetProductsQuery().OrderByDescending(p => p.ProductID);/*
* System.ServiceModel.DomainServices.Client.LoadOperation - 用于异步加载
* System.ServiceModel.DomainServices.Client.InvokeOperation - 用于异步调用
* System.ServiceModel.DomainServices.Client.SubmitOperation - 用于异步提交
*/
LoadOperation
<Product> lo = _context.Load(query);lo.Completed
+= delegate{
Data.Clear();
foreach (Product p in lo.Entities)
{
Data.Add(p);
}
};
}
public ICommand FilterCommand
{
get { return new FilterCommand(this); }
}
public ICommand InsertCommand
{
get { return new InsertCommand(this); }
}
public ICommand DeleteCommand
{
get { return new DeleteCommand(this); }
}
public ICommand UpdateCommand
{
get { return new UpdateCommand(this); }
}
// 检索数据
public void Filter(string productName)
{
EntityQuery<Product> query = _context.GetProductsQuery().Where(p => p.ProductName.Contains(productName));
LoadOperation
<Product> lo = _context.Load(query);lo.Completed
+= delegate{
Data.Clear();
foreach (Product p in lo.Entities)
{
Data.Add(p);
}
};
}
public void Insert(string productName)
{
EntitySet<Product> products = _context.EntityContainer.GetEntitySet<Product>();
Product product = new Product();
product.ProductName = productName;
product.CategoryID = 1;
product.SupplierID = 1;
products.Add(product);
_context.SubmitChanges(OnInsertCompleted, product);
}
{
if (!so.HasError)
{
Data.Insert(0, so.UserState as Product);
}
}
// 删除数据
public void Delete(List<Product> products)
{
EntitySet<Product> productsOriginal = _context.EntityContainer.GetEntitySet<Product>();
foreach (Product product in products)
{
productsOriginal.Remove(product);
}
_context.SubmitChanges(OnDeleteCompleted, products);
}
{
if (!so.HasError)
{
List<Product> products = so.UserState as List<Product>;
foreach (Product product in products)
{
Data.Remove(product);
}
}
}
// 更新数据
public void Update()
{
_context.SubmitChanges(OnUpdateCompleted, null);
}
private void OnUpdateCompleted(SubmitOperation so)
{
if (!so.HasError)
{
MessageBox.Show("更新成功");
}
}
}
}
InsertCommand.cs
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; namespace Silverlight40.WCFRIAServices.DomainServiceAndMVVM
{
/// <summary>
/// 插入的 Command
/// </summary>
public class InsertCommand : ICommand
{
private ProductViewModel _viewModel;
public InsertCommand(ProductViewModel viewModel)
{
_viewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
// 参数为:productName
public void Execute(object parameter)
{
var productName = (string)parameter;
_viewModel.Insert(productName);
}
}
}
DeleteCommand.cs
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 Silverlight40.Web.Model;
using System.Collections.Generic; namespace Silverlight40.WCFRIAServices.DomainServiceAndMVVM
{
/// <summary>
/// 删除的 Command
/// </summary>
public class DeleteCommand : ICommand
{
private ProductViewModel _viewModel;
public DeleteCommand(ProductViewModel viewModel)
{
_viewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
// 参数为:DataGrid.SelectedItems [System.Collections.IList 类型]
public void Execute(object parameter)
{
var collection = parameter as System.Collections.IList;
var products = new List<Product>();
foreach (Product product in collection)
{
products.Add(product);
}
_viewModel.Delete(products);
}
}
}
UpdateCommand.cs
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; namespace Silverlight40.WCFRIAServices.DomainServiceAndMVVM
{
/// <summary>
/// 更新的 Command
/// </summary>
public class UpdateCommand : ICommand
{
private ProductViewModel _viewModel;
public UpdateCommand(ProductViewModel viewModel)
{
_viewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_viewModel.Update();
}
}
}
FilterCommand.cs
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; namespace Silverlight40.WCFRIAServices.DomainServiceAndMVVM
{
/// <summary>
/// 查询的 Command
/// </summary>
public class FilterCommand : ICommand
{
private ProductViewModel _viewModel;
public FilterCommand(ProductViewModel viewModel)
{
_viewModel = viewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
// 参数为:productName
public void Execute(object parameter)
{
var productName = (string)parameter;
_viewModel.Filter(productName);
}
}
}
Demo.xaml
xmlns