ServiceStack.Northwind这个项目中提供了三表关联操作和缓存方式操作数据的示例。


主要的服务文件

CustomersService.cs :查询客户列表

OrdersService.cs : 查询一组订单以及和该组订单相关的订单项,其中每个订单包含客户信息和具体商品详情,共涉及到三个表。

CustomerDetailsService.cs 一个客户及其订单,被前一个服务(OrdersService)调用。


CachedServices.cs 使用缓存方式,对上面三个服务进行封装,缓存使用的MemoryCacheClient。


ServiceStack的缓存支持多种形式存储,包括Memory,Redis,MemoryCached,SQLAlchemy等,但是仅用于缓存自身的服务,并不是通用功能的缓存,所以使用范围很有限。


CustomersService.cs的代码,获取所有用户的列表,这个功能很简单,不加说明了。

publicCustomersResponseGet(Customersrequest){varcustomers=Db.Select<Customer>();returnnewCustomersResponse{Customers=customers};}


OrdersService.cs 的代码,用来获取多组订单信息,注意是多组,使用了.net集合处理的一些功能。这个服务先获取一组或一个订单,再根据订单获取订单详情信息,获取订单详情的时候根据订单ID对订单详情数据进行分组。


publicclassOrdersService:ServiceStack.ServiceInterface.Service{//指定分页式每页几条记录privateconstintPageCount=8;publicobjectGet(Ordersrequest){//获取一组或一个订单varorders=request.CustomerId.IsNullOrEmpty()?Db.Select<Order>(order=>order.OrderByDescending(o=>o.OrderDate)).Skip((request.Page.GetValueOrDefault(1)-1)*PageCount).Take(PageCount).ToList():Db.Select<Order>(order=>order.Where(o=>o.CustomerId==request.CustomerId).OrderByDescending(o=>o.CustomerId));if(orders.Count==0)returnnewOrdersResponse();//根据订单获取订单详情信息,并据订单ID对订单详情数据进行分组varorderDetails=Db.Select<OrderDetail>(detail=>Sql.In(detail.OrderId,orders.ConvertAll(x=>x.Id)));varorderDetailsLookup=orderDetails.ToLookup(o=>o.OrderId);varcustomerOrders=orders.ConvertAll(o=>newCustomerOrder{Order=o,OrderDetails=orderDetailsLookup[o.Id].ToList()});returnnewOrdersResponse{Results=customerOrders};}}

分步说明:1 订单列表

获取订单信息,判断传入的CustomerId 是否为空,如果CustomerId为空,执行分页方式查询订单的列表,分页的语法和EF中是相同的;如果有CustomerId,就会执行获取一条订单的操作。

varorders=request.CustomerId.IsNullOrEmpty()?Db.Select<Order>(order=>order.OrderByDescending(o=>o.OrderDate)).Skip((request.Page.GetValueOrDefault(1)-1)*PageCount).Take(PageCount).ToList():Db.Select<Order>(order=>order.Where(o=>o.CustomerId==request.CustomerId).OrderByDescending(o=>o.CustomerId));

根据获取的OrderId的列表,获取订单详情列表。

varorderDetails=Db.Select<OrderDetail>(detail=>Sql.In(detail.OrderId,orders.ConvertAll(x=>x.Id)));

其中

orders.ConvertAll(x=>x.Id)

的内容如下:

这个表达式

detail=>Sql.In(detail.OrderId,orders.ConvertAll(x=>x.Id))

实现的效果和SQL中的In子句对应,不过传入的参数有一点差异,第一个参数detail.OrderId指定字段名,第二个参数需要是一个×××值ID的列表,如上图跟踪时的oid的结构。



分步说明:2 分组的订单详情列表

在这个示例中orderDetails 变量查询后获得了44项数据。下一步根据OrderId对获得的这44项数据进行分组。

varorderDetailsLookup=orderDetails.ToLookup(o=>o.OrderId);

跟踪的结构如下图:

可以看到根据8个OrderId, 将44个订单详情数据分组成8组,并且是可以根据OrderId为索引,获取其中某一组的信息(在下一步我们可以看到这个过程)。

(ToLookup是.net集合中内置的一个函数,对集合中数据根据某一个字段进行分组)


分步说明:3 将订单列表和分组的详情列表组合

现在我们获得了8个订单项,还有44个根据订单的ID分组好的详情列表,下面我们把每一条订单的数据和对应的订单详情组合起来。

通过ConvertAll函数,逐项添加CustomerOrder,每个CustomerOrder包含有一个订单数据,和一组和该项订单相关的订单详情项。

varcustomerOrders=orders.ConvertAll(o=>newCustomerOrder{Order=o,OrderDetails=orderDetailsLookup[o.Id].ToList()});

跟踪的结果如下:


有8个订单项,每个订单包含有数量不等的订单详情项。也就是一个订单记录对应了多个购买的商品。


源代码下载:http://down.51cto.com/data/1976805