您的位置:首页 > 移动开发 > Objective-C

.NET 4.0 - Winform Control - DataGridView 数据绑定(ADO.NET Data Service)

2011-05-01 00:30 573 查看
ADO.NET Data Service 是一种基于REST架构的WCF + EF + OData(协议)的服务,.NET 客户端可以像引用其他WCF服务一样,添加services reference获得很好的客户端支持。客户端代理主要由 DataServiceContext 和 Entities 组成,因此客户端可以用类似 Linq2Entites 的方法获取 Data Service 的数据,底层框架将 Linq 语句转成 DataServiceQuery 再转成 HttpWebRequest 发起对服务的请求,并对返回的 HttpWebResponse 解析反序列化成实体。对 Data Service Client Library 的用户而言,事情很简单,执行效率也相应提高。但是其他语言的用户可就遭罪了,得自己拼接大量的字符串。其他详细参看:http://www.rainsts.net/article.asp?id=809 (雨痕的blog)。本篇文章,主要针对客户端调用来了解 Data Service 的特点。
 
1. 服务端的创建:
(1) 创建 WCF Application Service 工程
(2) 添加 ADO.NET Entity Data Model
(3) 删除既有的 .svc 文件,添加一个 AppFabric-enabled WCF Data Service
     (该模板可以通过 Extension Manager 在线下载) 
 


(4) 修改刚才添加的 DataService 类为如下:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class NorthwindDataService : DataService<NORTHWNDEntities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
// TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
// Examples:
// config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead);
// config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
config.SetEntitySetAccessRule("*", EntitySetRights.All);
RouteTable.Routes.Add(
new ServiceRoute("NorthwindDataService", new DataServiceHostFactory(), typeof(NorthwindDataService)));

}
}
2. 客户端添加 Service Reference



3. 要完成的任务:实现下面3个表的连动绑定并实现Update处理。



简单说明:
(1)  客户端每次访问 Data Service 都是调用一次 Http Request,默认使用的是 Atom XML 格式。
       (Execute,LoadProperty, SaveChanges等方法)
(2)  DataServiceContext 会将查询过的数据在客户端缓存,并对缓存的数据进行 State Tracing。
       直到 DataServiceContext 被销毁。可以通过 DataServiceContext.Entities 获得跟踪实体的实例。
(3)  因为在客户端缓存了数据,所以存在普遍的并发风险。另外查询时,会根据 MergeOptions 来更新客户端缓存。
(4)  Navigation Property 在客户端的实体里不支持,关联数据需要手动查询,可以利用(LoadProperty方法)
      提交的时候可以用: SetLink, AddLink, DeleteLink 进行关联。
(5)  将数据提交到服务端需要先对应调用下面的方法:
      添加 -- AddToXXX 或者 AddObject(string entitySetName, object entity);
      更新 -- UpdateObject(object entity);
      删除 -- DeleteObject(object entity);
      最后调用 SaveChanges() 方法
(6)  Linq2DataService 返回的是 DataServiceQuery<T> (封装的是请求的Uri),
      需要调用Execute(同步)或者BeginExecute(异步)才能获取结果。
(7) 每一个实体都对应服务端一个Identity(uri)
 
客户端UI:



根据上面说明的第(5)条,数据提交之前必须调用UpdateObject方法,因此可以利用 BindingSource 的ListChanged 事件即时调用UpdateObject,等"Update"按钮事件处理方法中直接调用 SaveChanges 方法就可以了。 
 
客户端代码:详细看注释
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Services.Client;
using System.Collections.ObjectModel;
using System.Net;

namespace WcfDataServiceClient
{
public partial class DataBindDemo : Form
{

public DataBindDemo()
{
InitializeComponent();
}

private NorthwindDataSvc.NORTHWNDEntities northwind;

private void Form1_Load(object sender, EventArgs e)
{
// 将地址设置到TcpTracer监听的20000端口上,TcpTracer将转发至服务的真实IP:58960
var svcUri = new Uri("http://localhost:20000/NorthwindDataService.svc");
northwind = new NorthwindDataSvc.NORTHWNDEntities(svcUri);
// 绑定数据,最初只有customers
BindData();

// 为了避免绑定时触发 SelectedIndexChanged 事件,
// SelectedIndexChanged 事件的绑定放在Customers数据加载之后
// 绑定customers的选择变更事件,加载orders
lstCustomer.SelectedIndexChanged += new EventHandler(lstCustomer_SelectedIndexChanged);
// 绑定orders的选择变更事件,加载order_details
dgvOrders.SelectionChanged += new EventHandler(dgvOrders_SelectionChanged);

// 绑定各BindingSource的ListChanged事件,修改缓存状态
customerBindingSource.ListChanged += new ListChangedEventHandler(UpdateEntity);

// 触发一次SelectedIndexChanged, 加载orders和order_detailss
lstCustomer.SelectedIndex = -1;
lstCustomer.SelectedIndex = 0;
}

private void UpdateEntity(object sender, ListChangedEventArgs e)
{
if (e.ListChangedType != ListChangedType.ItemChanged) return;
// 从BindingSource中获取当前变更的数据
var data = ((BindingSource)sender).Current;
// 告知本地缓存该数据发生变更
northwind.UpdateObject(data);
}

private void lstCustomer_SelectedIndexChanged(object sender, EventArgs e)
{
var customer = lstCustomer.SelectedItem as NorthwindDataSvc.Customer;
if (customer == null) return;
orderBindingSource.ListChanged -= UpdateEntity;
// 这里DataService里没有Navigation Property,
// customer.Orders(DataServiceCollection<T>)并没有数据
// 在SaveChanges之前都使用客户端数据
northwind.MergeOption = MergeOption.PreserveChanges;
northwind.LoadProperty(customer, "Orders");
orderBindingSource.DataSource = customer.Orders;
dgvOrders.DataSource = orderBindingSource;
orderBindingSource.ListChanged += UpdateEntity;
}

private void dgvOrders_SelectionChanged(object sender, EventArgs e)
{
if (dgvOrders.SelectedRows.Count <= 0) return;
orderDetailBindingSource.ListChanged -= UpdateEntity;
var order = dgvOrders.BindingContext[dgvOrders.DataSource].Current as NorthwindDataSvc.Order;
northwind.MergeOption = MergeOption.PreserveChanges;
northwind.LoadProperty(order, "Order_Details");
orderDetailBindingSource.DataSource = order.Order_Details.ToList();
dgvOrderDetails.DataSource = orderDetailBindingSource;
orderDetailBindingSource.ListChanged += UpdateEntity;
}

private void BindData()
{
customerBindingSource.DataSource = northwind.Customers.Execute().ToList();
lstCustomer.DataSource = customerBindingSource;
lstCustomer.ValueMember = "ContactName";
lstCustomer.DisplayMember = "ContactName";

txtName.DataBindings.Add("Text", customerBindingSource, "ContactName");
txtContactTitle.DataBindings.Add("Text", customerBindingSource, "ContactTitle");
txtAddress.DataBindings.Add("Text", customerBindingSource, "Address");
txtCity.DataBindings.Add("Text", customerBindingSource, "City");
txtRegion.DataBindings.Add("Text", customerBindingSource, "Region");
txtPostalCode.DataBindings.Add("Text", customerBindingSource, "PostalCode");
txtPhone.DataBindings.Add("Text", customerBindingSource, "Phone");
txtFax.DataBindings.Add("Text", customerBindingSource, "Fax");
txtCountry.DataBindings.Add("Text", customerBindingSource, "Country");
}

private void btnUpdate_Click(object sender, EventArgs e)
{
try
{
// 获得DataServiceContext中跟踪的Entities中的变更过的数据
var changedEntities = northwind.Entities.
Where(et => et.State != EntityStates.Unchanged).ToList();
string log = string.Format("Have [{0}] datas been changed.\n", changedEntities.Count);
foreach (var entity in changedEntities)
log += entity.ServerTypeName + ":" + entity.State + "\n";
MessageBox.Show(log);
// 如果有变更
if (changedEntities.Count > 0)
{
// 批量提交数据(即数据在一个Request内提交)
var resp = northwind.SaveChanges(SaveChangesOptions.Batch);
MessageBox.Show(((HttpStatusCode)resp.BatchStatusCode).ToString());
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
try
{
// 获得DataServiceContext中跟踪的Entities中的变更过的数据
var changedEntities = northwind.Entities.Where(et => et.State != EntityStates.Unchanged);
// 指定更新行为:如果本地数据不一致则用服务端数据覆盖
northwind.MergeOption = MergeOption.OverwriteChanges;
foreach (var entity in changedEntities)
{
// 无论请求成功还是失败,重新查询把跟踪对象的State改为Unchanged.
northwind.Execute<object>(new Uri(entity.Identity)).ToList();
}
}
catch
{
}
}
}

private void btnFirst_Click(object sender, EventArgs e)
{
customerBindingSource.MoveFirst();
}

private void btnPre_Click(object sender, EventArgs e)
{
customerBindingSource.MovePrevious();
}

private void btnNext_Click(object sender, EventArgs e)
{
customerBindingSource.MoveNext();
}

private void btnLast_Click(object sender, EventArgs e)
{
customerBindingSource.MoveLast();
}
}
}
执行成功的话,将会获得 Accept 的 ResponseStatus





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐