//增加 object CreateResource(string containerName, string fullTypeName); //修改 void SetValue(object targetResource, string propertyName, object propertyValue); //删除 void DeleteResource(object targetResource); //保存 void SaveChanges(); //回滚 void ClearChanges();PS:实体关联关系的一系列操作,比较复杂,之后讨论。
另外需要提到的是 IDataServiceUpdateProvider 接口设计中支持批量特性,这就允许在一个事务中一次更新很多的资源。换句话说可以在 SaveChangeds() 方法调用前,调用 IDataServiceUpdateProvider.SetValue() 或者 CreateResource() 多次。这似乎看起来比较简单,但是对接口的实现却影响很大。在某个方法实现上,不可以立即将请求反映到数据源上,而是记录所发生的事情并在最后一次性的提交所有操作。
如果数据存放在数据库中,那么数据库系统会自动的在事务中记录所有的命令操作(比如:Entity Framewok)。但在这个例子中使用了内存对象存放数据,所以需要记录在 SaveChanges() 前所发生的一切。
因此在 DataModel 中,增加了 List<Action> _actions 来记录 SaveChanges() 之前的操作(请求)。
然后在 CreateResource, SetValue, DeleteResource 时都只是将操作暂存在 _actions 里。
SaveChanges 时 ForEach 所有暂存的 Action,一口气调用。 ClearChanges 则简单的把 _actions 清空。
public class DataModel : IDataServiceUpdateProvider { #region Populate Service Data static IList<Order> _orders; static IList<Item> _items; List<Action> _actions = new List<Action>(); static DataModel() { _orders = new List<Order> { new Order(){ OrderId=1, Customer = "Wendy Wu", Items = new List<Item>()}, new Order(){ OrderId=2, Customer = "John Gu", Items = new List<Item>()}, new Order(){ OrderId=3, Customer = "Balance Yao", Items = new List<Item>()} }; _items = new List<Item> { new Item(){ Product="Chang", Quantity = 4 }, new Item(){ Product="Aniseed Syrup", Quantity=5 }, new Item(){ Product="Toy", Quantity=7 }, new Item(){ Product="Car", Quantity=1 }, new Item(){ Product="Ball", Quantity=6 } }; _orders[0].Items.Add(_items[0]); _orders[1].Items.Add(_items[1]); _orders[1].Items.Add(_items[2]); _orders[2].Items.Add(_items[3]); _orders[2].Items.Add(_items[4]); } #endregion public IQueryable<Order> Orders { get { return _orders.AsQueryable<Order>(); } } public IQueryable<Item> Items { get { return _items.AsQueryable<Item>(); } } #region NotImplementedMethods public void SetConcurrencyValues(object resourceCookie, bool? checkForEquality, IEnumerable<KeyValuePair<string, object>> concurrencyValues) { throw new NotImplementedException(); } public void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded) { //PropertyInfo pi = targetResource.GetType().GetProperty(propertyName); //if (pi == null) // throw new Exception("Can't find property"); //IList collection = (IList)pi.GetValue(targetResource, null); //collection.Add(resourceToBeAdded); } public void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved) { //PropertyInfo pi = targetResource.GetType().GetProperty(propertyName); //if (pi == null) // throw new Exception("Can't find property"); //IList collection = (IList)pi.GetValue(targetResource, null); //collection.Remove(resourceToBeRemoved); } public void SetReference(object targetResource, string propertyName, object propertyValue) { //((IUpdatable)this).SetValue(targetResource, propertyName, propertyValue); } #endregion public object CreateResource(string containerName, string fullTypeName) { Type t = Type.GetType(fullTypeName, true); object resource = Activator.CreateInstance(t); _actions.Add(() => { if (containerName == "Orders") _orders.Add(resource as Order); if (containerName == "Items") _items.Add(resource as Item); }); return resource; } public object GetResource(IQueryable query, string fullTypeName) { object resource = query.Cast<object>().SingleOrDefault(); // fullTypeName can be null for deletes if (fullTypeName != null && resource.GetType().FullName != fullTypeName) throw new ApplicationException("Unexpected type for this resource."); return resource; } public void DeleteResource(object targetResource) { if (targetResource.GetType() == typeof(Order)) { _orders.Remove(targetResource as Order); return; } if (targetResource.GetType() == typeof(Item)) { _items.Remove(targetResource as Item); return; } throw new NotSupportedException("Type not found"); } public void SetValue(object targetResource, string propertyName, object propertyValue) { _actions.Add(() => { targetResource .GetType() .GetProperties() .Single(p => p.Name == propertyName) .GetSetMethod() .Invoke(targetResource, new[] { propertyValue }); }); } public object GetValue(object targetResource, string propertyName) { var value = targetResource .GetType() .GetProperties() .Single(p => p.Name == propertyName) .GetGetMethod() .Invoke(targetResource, new object[] { }); return value; } public object ResetResource(object resource) { return resource; } public object ResolveResource(object resource) { return resource; } public void SaveChanges() { _actions.ForEach(a => a()); // Handler Primary Keys var newOrders = _orders.Where(o => o.OrderId == 0).ToList(); var maxOrderId = _orders.Max(o => o.OrderId); foreach (var order in newOrders) order.OrderId = ++maxOrderId; } public void ClearChanges() { _actions.Clear(); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Services.Client; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { var svcUri = new Uri("http://localhost:50480/WcfDataService1.svc"); var ctx = new DataSvc.DataModel(svcUri); Console.WriteLine("[Orders]"); ctx.Orders.ToList().ForEach(o => Console.WriteLine("\t{0}", o.Customer)); Console.WriteLine("---------------"); Console.WriteLine(); var order = ctx.Orders.Where(o => o.OrderId == 2).First(); Console.WriteLine("1.查询OrderId=2的Order.Customer:"); Console.WriteLine("\t{0}", order.Customer); // 括号里的"2"是对应Order主键而不是Index var items = ctx.Execute<DataSvc.Item>(new Uri("/Orders(2)/Items", UriKind.Relative)).ToList(); Console.WriteLine("2.查询OrderId=2的Order.Items:"); items.ForEach(it => Console.WriteLine("\t{0}", it.Product)); Console.WriteLine("3.增加Order:"); Console.WriteLine("\t保存前的Count:" + ctx.Orders.Count()); var addOrder1 = new DataSvc.Order { Customer = "Customer" + Guid.NewGuid().ToString("N") }; ctx.AddToOrders(addOrder1); var addOrder2 = new DataSvc.Order { Customer = "Customer" + Guid.NewGuid().ToString("N") }; ctx.AddToOrders(addOrder2); ctx.SaveChanges(); Console.WriteLine("\t保存后的Count:" + ctx.Orders.Count()); Console.WriteLine("4.修改OrderId=2的Order.Customer:"); Console.WriteLine("\t保存前的Customer:" + order.Customer); order.Customer = "Clark Li"; ctx.SaveChanges(); var query = ctx.Orders.Where(o => o.OrderId == 2).First(); Console.WriteLine("\t保存后的Customer:" + query.Customer); Console.WriteLine("5.删除Order:"); Console.WriteLine("\t保存前的Count:" + ctx.Orders.Count()); var delOrder1 = ctx.Orders.Where(o => o.OrderId == addOrder1.OrderId).First(); ctx.DeleteObject(delOrder1); ctx.SaveChanges(); Console.WriteLine("\t保存后的Count:" + ctx.Orders.Count()); Console.WriteLine(); Console.WriteLine("[Orders]"); ctx.Orders.ToList().ForEach(o => Console.WriteLine("\t{0}", o.Customer)); Console.WriteLine("---------------"); Console.Read(); } } }