[索引页]
[×××]


精进不休 .NET 4.0 (6) - ADO.NET Data Services 1.5 新特性


作者: webabcd


介绍
ADO.NET Data Services 1.5 的新增功能
  • 支持服务端的 RowCount - 获取指定实体集合的成员数(只返回一个整型值,而不会返回实体集合) 
  • 支持服务端的分页 - 服务端可以返回分页后的数据,并且在其中还可以包含全部数据总数 
  • 支持服务端的 Select - 返回的结果只包括 Select 的字段 
  • 支持大数据传输 BLOB(binary large object)
  • 支持自定义数据服务 


示例
1、服务端 RowCount 的 Demo
MyDataService.svc.cs
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;

namespace DataAccess.DataServices.Service
{
        [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
         public class MyDataService : DataService
        {
static void InitializeService() static void InitializeService(DataServiceConfiguration config)
                {
                        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
                        config.SetEntitySetAcce***ule( "Products", EntitySetRights.All);

                        // SetEntitySetPageSize( string name, int size) - 新增的方法。用于提供分页后的数据
                        //         string name - 指定需要用于分页的实体集合
                        //         int size - 分页的页大小
                        config.SetEntitySetPageSize( "Products", 5);
                }
        }
}
 
RowCount.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace DataAccess.DataServices
{
         public partial class RowCount : System.Web.UI.Page
        {
void Page_Load() void Page_Load(object sender, EventArgs e)
                {
                        MyDataServiceProxy.AdventureWorksEntities context = new MyDataServiceProxy.AdventureWorksEntities( new Uri( "http://localhost:9046/DataServices/Service/MyDataService.svc/"));

                        // 支持服务端的 RowCount - 获取指定实体集合的成员数(只返回一个整型值,而不会返回实体集合)
                        var productCount = context.Products.Count();
                        Response.Write(productCount.ToString());
                }
        }
}

/*
$count - 返回 RowCount,即对应集合的成员数(只返回一个整型值,而不会返回实体集合)
http://localhost:9046/DataServices/Service/MyDataService.svc/Products/$count

$inlinecount=none - 只返回实体集合(分页后的数据)
http://localhost:9046/DataServices/Service/MyDataService.svc/Products?$inlinecount=none

$inlinecount=allpages - 在返回实体集合的基础上(分页后的数据),其中还会包括一个实体集合成员数(分页前的数据)的字段
http://localhost:9046/DataServices/Service/MyDataService.svc/Products?$inlinecount=allpages
*/
 
 
2、服务端分页的 Demo
MyDataService.svc.cs
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;

namespace DataAccess.DataServices.Service
{
        [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
         public class MyDataService : DataService
        {
static void InitializeService() static void InitializeService(DataServiceConfiguration config)
                {
                        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
                        config.SetEntitySetAcce***ule( "Products", EntitySetRights.All);

                        // SetEntitySetPageSize( string name, int size) - 新增的方法。用于提供分页后的数据
                        //         string name - 指定需要用于分页的实体集合
                        //         int size - 分页的页大小
                        config.SetEntitySetPageSize( "Products", 5);
                }
        }
}
 
Paging.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace DataAccess.DataServices
{
         public partial class Paging : System.Web.UI.Page
        {
void Page_Load() void Page_Load(object sender, EventArgs e)
                {
                        MyDataServiceProxy.AdventureWorksEntities context = new MyDataServiceProxy.AdventureWorksEntities( new Uri( "http://localhost:9046/DataServices/Service/MyDataService.svc/"));

                        // 支持服务端的分页 - 服务端可以返回分页后的数据,并且在其中还可以包含全部数据总数
                        //         服务端代码:config.SetEntitySetPageSize( "Products", 5); 表示每页最多 5 条数据
                        //         客户端代码:通过 Skip() 方法来控制需要跳过的记录数
                        var products = context.Products.Skip(10);

                        foreach (var product in products)
                        {
                                Response.Write(product.ProductID.ToString() + "
"
);
                        }
                }
        }
}

/*
$skip=[int] - 指定需要跳过的记录数
http://localhost:9046/DataServices/Service/MyDataService.svc/Products?$skip=10

$inlinecount=none - 只返回实体集合(分页后的数据)
http://localhost:9046/DataServices/Service/MyDataService.svc/Products?$inlinecount=none

$inlinecount=allpages - 在返回实体集合的基础上(分页后的数据),其中还会包括一个实体集合成员数(分页前的数据)的字段
http://localhost:9046/DataServices/Service/MyDataService.svc/Products?$inlinecount=allpages
*/
 
 
3、服务端 Select 的 Demo
MyDataService.svc.cs
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;

namespace DataAccess.DataServices.Service
{
        [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
         public class MyDataService : DataService
        {
static void InitializeService() static void InitializeService(DataServiceConfiguration config)
                {
                        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
                        config.SetEntitySetAcce***ule( "Products", EntitySetRights.All);

                        // SetEntitySetPageSize( string name, int size) - 新增的方法。用于提供分页后的数据
                        //         string name - 指定需要用于分页的实体集合
                        //         int size - 分页的页大小
                        config.SetEntitySetPageSize( "Products", 5);
                }
        }
}
 
QueryProjection.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace DataAccess.DataServices
{
         public partial class QueryProjection : System.Web.UI.Page
        {
void Page_Load() void Page_Load(object sender, EventArgs e)
                {
                        MyDataServiceProxy.AdventureWorksEntities context = new MyDataServiceProxy.AdventureWorksEntities( new Uri( "http://localhost:9046/DataServices/Service/MyDataService.svc/"));

                        // 支持服务端的 Select - 返回的结果只包括 Select 的字段
                        var products = context.Products. Select(p => new { ProductID = p.ProductID, Name = p.Name });

                        foreach (var product in products)
                        {
                                Response.Write(product.ProductID.ToString() + ": " + product.Name + "
"
);
                        }
                }
        }
}

/*
$ select=[column1,column2,column3,...] - 返回的实体集合数据中只包括指定的字段
http://localhost:9046/DataServices/Service/MyDataService.svc/Products/?$ select=ProductID,Name
*/
 
 
4、BLOB 的 Demo
BLOBService.svc.cs
/*
ADO.NET Data Services 1.5 - 新增了对大数据传输 BLOB(binary large object)的支持
需要在概念模型(ConceptualModels)中的相关实体上增加属性“m:HasStream= "true" xmlns:m= "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
*/

using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;

using System.IO;

namespace DataAccess.DataServices.Service
{
        [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
         public class BLOBService : DataService, IServiceProvider
        {
static void InitializeService() static void InitializeService(DataServiceConfiguration config)
                {
                        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
                        config.SetEntitySetAcce***ule( "Products", EntitySetRights.All);
                }

object GetService() object GetService(Type serviceType)
                {
                         if (serviceType != typeof(System.Data.Services.Providers.IDataServiceStreamProvider))
                                return null;

                        // 调用服务的时候,如果指定了需要流式传输大数据对象,则通过我们自定义的流式文件传输对象去处理
                        return new ProductPhotoStreamProvider();
                }
        }

        ///
        /// 自定义的一个流式文件传输类,需要实现 System.Data.Services.Providers.IDataServiceStreamProvider 接口
        ///

         public class ProductPhotoStreamProvider : System.Data.Services.Providers.IDataServiceStreamProvider
        {
                ///
                /// 获取流。将某个实体的某个属性以流类型的方式返回
                ///

                /// "entity">相关的实体
                /// "operationContext">当前数据服务请求的上下文
                ///
Stream GetReadStream() Stream GetReadStream(object entity, string etag, bool? checkETagForEquality, DataServiceOperationContext operationContext)
                {
                         if (entity as MyEntity.Product == null)
                                return null;

                        int productId = (entity as MyEntity.Product).ProductID;

                        using (var context = new MyEntity.AdventureWorksEntities())
                        {
                                var product = context.Products.First(p => p.ProductID == productId);
                                var stream = new MemoryStream(product.ThumbNailPhoto);
                                return stream;
                        }
                }

Uri GetReadStreamUri() Uri GetReadStreamUri(object entity, DataServiceOperationContext operationContext)
                {
                        return null;
                }

                // 流的内容类型
string GetStreamContentType() string GetStreamContentType(object entity, DataServiceOperationContext operationContext)
                {
                        return "p_w_picpath/jpeg";
                }

string GetStreamETag() string GetStreamETag(object entity, DataServiceOperationContext operationContext)
                {
                        return null;
                }

                // 流的缓冲区大小
                 public int StreamBufferSize
                {
                         get { return 64; }
                }

void DeleteStream() void DeleteStream(object entity, DataServiceOperationContext operationContext)
                {
                        throw new NotImplementedException();
                }

System.IO.Stream GetWriteStream() System.IO.Stream GetWriteStream(object entity, string etag, bool? checkETagForEquality, DataServiceOperationContext operationContext)
                {
                        throw new NotImplementedException();
                }

string ResolveType() string ResolveType( string entitySetName, DataServiceOperationContext operationContext)
                {
                        throw new NotImplementedException();
                }
        }
}
 
BLOB.aspx
<%@ Page Title= "" Language="C# " MasterPageFile="~/Site.Master " AutoEventWireup=" true"
        CodeBehind= "BLOB.aspx.cs" Inherits= "DataAccess.DataServices.BLOB" %>

"Content1" ContentPlaceHolderID= "head" runat= "server">

"Content2" ContentPlaceHolderID= "ContentPlaceHolder1" runat= "server">

        

        
        "http://localhost:9046/DataServices/Service/BLOBService.svc/Products(714)/$value" alt= "p_w_picpath" />

 
 
5、自定义数据服务的 Demo
CustomDataService.svc.cs
/*
ADO.NET Data Services 1.5 - 新增了对自定义数据服务的支持    
*/

using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;

namespace DataAccess.DataServices.Service
{
        [System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
         public class CustomDataService : DataService
        {
static void InitializeService() static void InitializeService(DataServiceConfiguration config)
                {
                        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
                        config.SetEntitySetAcce***ule( "Orders", EntitySetRights.All);
                        config.SetEntitySetAcce***ule( "Products", EntitySetRights.All);
                }
        }

        ///
        /// 数据上下文
        ///

         public class OrderContext
        {
                static List _orders;
                static List _products;
                static OrderContext()
                {
                        _orders = new List
                        {
                                 new Order { OrderId = 0, Customer= "webabcd"},
                                 new Order { OrderId = 1, Customer= "webabcdefg"}
                        };

                        _products = new List
                        {
                                 new Product { ProductId = 0, ProductName= "wii", Price=100 },    
                                 new Product { ProductId = 1, ProductName= "xbox360", Price=200 },    
                                 new Product { ProductId = 2, ProductName= "ps3", Price = 300 },    
                                 new Product { ProductId = 3, ProductName= "nds", Price=50 },
                                 new Product { ProductId = 4, ProductName= "psp", Price=100 }
                        };

                        _orders[0].Items.Add(_products[0]);
                        _orders[0].Items.Add(_products[1]);

                        _orders[1].Items.Add(_products[2]);
                        _orders[1].Items.Add(_products[3]);
                        _orders[1].Items.Add(_products[4]);
                }


                 public IQueryable Orders
                {
                         get { return _orders.AsQueryable(); }
                }

                 public IQueryable Products
                {
                         get { return _products.AsQueryable(); }
                }
        }

        /*
         * DataServiceKeyAttribute() - 指定主键字段
         * EntityPropertyMapping() - 实体属性到 ATOM 字段的映射,以便生成一个友好格式的 Feed    
         */
        [EntityPropertyMapping( "Customer", SyndicationItemProperty.AuthorName, SyndicationTextContentKind.Plaintext, true)]
        [DataServiceKeyAttribute( "OrderId")]
         public class Order
        {
                 public int OrderId { get; set; }
                 public string Customer { get; set; }

                 private List _items;
                 public List Items
                {
                         get
                        {
                                 if (_items == null)
                                        _items = new List();

                                return _items;
                        }
                         set
                        {
                                _items = value;
                        }
                }
        }

        [DataServiceKeyAttribute( "ProductId")]
         public class Product
        {
                 public int ProductId { get; set; }
                 public string ProductName { get; set; }
                 public int Price { get; set; }
        }
}
 
CustomDataService.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace DataAccess.DataServices
{
         public partial class CustomDataService : System.Web.UI.Page
        {
void Page_Load() void Page_Load(object sender, EventArgs e)
                {
                        // 使用自定义数据服务提供的服务
                        CustomDataServiceProxy.OrderContext context = new CustomDataServiceProxy.OrderContext( new Uri( "http://localhost:9046/DataServices/Service/CustomDataService.svc/"));

                        var orders = context.Orders;

                        foreach (var order in orders)
                        {
                                Response.Write(order.OrderId.ToString() + "
"
);
                        }
                }
        }
}
 
 
注:
以 URI 语法的方式查询 ADO.NET 数据服务的形式如下:
http://[Url]/[ServiceName]/[EntityName]/[NavigationOptions]?[QueryOptions]
详细语法参看 MSDN


OK
[×××]