博客
关于我
ERP/MIS开发 LLBL Gen多表操作
阅读量:395 次
发布时间:2019-03-05

本文共 6891 字,大约阅读时间需要 22 分钟。

前一篇文章中提到,LLBL Gen对单个表的查询,这里再来分析一下LLBL Gen对多表的操作。

Adapter模式,用到的变量adapter定义为DataAccessAdapter adapter=new DataAccessAdapter ();

主从表的查询,保存和删除

SalesOrder是采购单主表,它下面有明细表SalesOrderDetail,用于记录采购单的物料信息。

查询编号为OE20100821的采购单及其物料明细
SalesOrderEntity salesOrder=new SalesOrderEntity (“OE20100821”);
IPrefetchPath2 prefetchPath = new PrefetchPath2((int)EntityType.SalesOrderEntity);

prefetchPath.Add(SalesOrderEntity.PrefetchPathSalesOrderDetails);

bool found = adapter.FetchEntity(salesOrder, prefetchPath, null, null);
PrefetchPath为因深度不同,一次可读取多个表的记录到内存中。LLBL Gen要求明确指定需要读取的从表深度。
保存采购单及其物料明细。先保存采购单主表,再保存从表采购单明细
SalesOrderEntity salesOrder=new SalesOrderEntity (“OE20100821”);
adapter.SaveEntity(salesOrder, true, false);
foreach (SalesOrderDetailEntity detail in salesOrder.SalesOrderDetails)
{
       adapter.SaveEntity(detail);   

}

删除采购单。先删除从表采购单明细,再删除采购单主表
SalesOrderEntity salesOrder;//OrderNo=”OE20100821”
foreach (SalesOrderDetailEntity detail in salesOrder.SalesOrderDetails)
{
       adapter.DeleteEntity(detail);   

}

adapter.DeleteEntity(salesOrder);

LLBL Gen框架可以区分INSERT/UPDATE命令,统一用方法SaveEntity即可。

判断实体是新增加的还是从数据库中读取的,可用如下的方法
bool loadedCorrectly = (salesOrder.Fields.State == EntityState.Fetched);

 

自定义查询TypedList,可用于从多个表中读取任意的字段数据

SQL语句如下,这个例子也演示了表达式的用法。

SELECT OrderID,ProductID,(UnitPrice * Quantity) AS RowTotal FROm [Order Details]
对应的LLBL Gen的写法如下
ResultsetFields fields = new ResultsetFields(3);

fields.DefineField(OrderDetailsFields.OrderId, 0);

fields.DefineField(OrderDetailsFields.ProductId, 1);

fields.DefineField(new EntityField2("RowTotal",(OrderDetailsFields.UnitPrice * OrderDetailsFields.Quantity)), 2);

DataTable results = new DataTable();

DataAccessAdapter adapter = new DataAccessAdapter();

adapter.FetchTypedList(fields, results, null);

再来看一个复杂的从多表中查询结果的例子
先定义存放结果的DataTable,根据字段需要设计对应的表结构

DataTable inventoryBalance= new FastSerializableDataTable("InventoryBalance");

inventoryBalance.Columns.Add("Loc", typeof(string));
inventoryBalance.Columns.Add("Description", typeof(string));
inventoryBalance.Columns.Add("QtyOnHand", typeof(decimal));
inventoryBalance.Columns.Add("QtyOnInspect", typeof(decimal));
定义数据项的来源

ResultsetFields inventoryBalanceFields = new ResultsetFields(4);

inventoryBalanceFields .DefineField(InventoryBalanceFields.Loc, 0);
inventoryBalanceFields .DefineField(LocationFields.Description, 1);
inventoryBalanceFields .DefineField(InventoryBalanceFields.QtyOnHand, 2);
inventoryBalanceFields .DefineField(InventoryBalanceFields.QtyOnInspect, 3);
定义查询过滤条件
IRelationPredicateBucket filterBucket = new RelationPredicateBucket();
filterBucket.PredicateExpression.Add(InventoryBalanceFields.ItemNo == itemNo);
设定以上数据来源项的表之间的关系
filterBucket.Relations.Add(InventoryBalanceEntity.Relations.LocationEntityUsingLoc);

对结果排序

ISortExpression sorter = new SortExpression(InventoryBalanceFields.ItemNo | SortOperator.Ascending)

最后加载数据到内存表中

adapter.FetchTypedList(inventoryBalanceFields, inventoryBalance, filterBucket, 0, sorter, false, null);
仓库LocationEntity与库存余额InventoryBalanceEntity的对应关系是一对一,使用Loc仓库编码来关联。
           
这个查询还可以复杂一些,要查询的字段不一定是数据库有的,比如聚合(求和,求平均值)函数的结果。
我们在为上面的查询添加一个字段,ORM写法如下,表示已经下采购单的物料合计数量
DbFunctionCall dbFunQtyUnused = new DbFunctionCall("ISNULL", new object[]  { (SalesOrderDetailFields.QtyOrdered), 0 });
EntityField2 eQtyOrder = new EntityField2("QtyOrdered", dbFunQtyUnused);
inventoryBalanceFields.DefineField(eQtyOrder , 4, "QtyOrdered");
inventoryBalanceFields[4].AggregateFunctionToApply = AggregateFunction.Sum;

因为新加入了表SalesOrderEntity,需要增加关系,与仓库关联为采购单的每一笔物料的进仓仓库。

filterBucket.Relations.Add(InventoryBalanceEntity.Relations.SalesOrderDetailEntityUsingLoc);

 

子查询 Scalar query expressions

先看一个例子,SQL语句如下,查询客户表中的客户编号及其所有的订单合计数量

SELECT CustomerID,
( SELECT COUNT(*) FROM Orders WHERE CustomerID = Customers.CustomerID ) AS NumberOfOrders FROM Customers

Adapter模式的ORM的写法如下

ResultsetFields fields = new ResultsetFields(2);
fields.DefineField(CustomerFields.CustomerID, 0);
fields.DefineField(new EntityField2("NumberOfOrders", new ScalarQueryExpression(OrderFields.OrderId.SetAggregateFunction(AggregateFunction.Count), (CustomerFields.CustomerId == OrderFields.CustomerId))), 1);
DataTable results = new DataTable();
adapter.FetchTypedList(fields, results, null);
如果只需要查询单个值,则DataAccessAdapter有更直接的支持,请看下面的例子
IRelationPredicateBucket filterBucket = new RelationPredicateBucket();

filterBucket.PredicateExpression.Add(SalesOrderDetailFields.ItemNo == ‘PC’);

filterBucket.PredicateExpression.Add(SalesOrderFields.OrderNo== ‘OE20110921’);
filterBucket.Relations.Add(SalesOrderEntity.Relations.SalesOrderDetailEntityUsingOrderNo);
DbFunctionCall dbFunQtyOrdered = new DbFunctionCall("IsNull", new object[] { (SalesOrderDetailFields.QtyOrdered), 0 });
object result = adapter.GetScalar(SalesOrderDetailFields.QtyOrdered, dbFunQtyOrdered , AggregateFunction.Sum, filterBucket);
这段ORM语句是要查询采购单OE20110921中的物料为PC的物料合计数量,用SQL写出来就是
SELECT SUM(QtyOrdered) FROM SalesOrder a, SalesOrderDetail b WHERE a.OrderNo=b.OrderNo
AND a.OrderNo=’OE20110921’ AND b.ItemNo=’PC’
聚合函数应用的场景,常常如下所示,就是需要构建结果集ResultsetFields
ResultsetFields fields = new ResultsetFields(2);
fields.DefineField(CustomerFieldIndex.Country, 0, "Country");
fields.DefineField(CustomerFieldIndex.CustomerID, 1, "AmountCustomers");
fields[1].AggregateFunctionToApply = AggregateFunction.CountDistinct

 

EntityCollection的查询

要查询的数据如果来源于数据库,可以应用以上的几种方法,如果要查询的数据来源于内存集合,则应用下面的模式。

比如,要找出采购单明细表中未出货的物料,则应用以下的写法
List<int> indices = SalesOrderDetails.FindMatches(SalesOrderDetailFields.QtyPacked <= 0);
for (int i = indices.Count - 1; i >= 0; i--)
{
       SalesOrderDetails unPackedOrder=SalesOrderDetails[indices[i]);
}
FindMatches方法也可以传入下面的类型

IPredicate filterBucket = (SalesOrderDetailFields.QtyPacked <= 0);

如果要操作的数据有先后之分,并且些时EntityCollection中的数据不是业务规则操作需要的顺序,则可以以下面的模式,用EntityView2来排序过滤数据,重新获取按照指定规则排序的数据。
IPredicate filterBucket = (SalesOrderDetailFields.ItemNo == “PC”);
ISortExpression sortExpression = new SortExpression();
sortExpression.Add(SalesOrderDetailFields.ItemNo| SortOperator.Ascending);

EntityCollection<SalesOrderDetailEntity> detailEntities = SalesOrder.SalesOrderDetails;

EntityView2<SalesOrderDetailEntity> entityView = new EntityView2<SalesOrderDetailEntity>(detailEntities);

entityView.Filter = filterBucket;
entityView.Sorter = sortExpression;
关键的三句,依据EntityCollection构造EntityView2,并且传入指定的排序和过滤条件。
EntityCollection<SalesOrderDetailEntity> tmpCollection = (EntityCollection<SalesOrderDetailEntity>)entityView.ToEntityCollection();
foreach (SalesOrderDetailEntity detail in tmpCollection)
{
   //在这里,采购单中的物料明细已经按照物料编号升序排序了
}

自从应用ORM后,很少写SELECT * 这样的查询语句,因为这样太耗费时间,影响Performance,这种模式如下

IncludeFieldsList fieldList = new IncludeFieldsList();
fieldList.Add(SalesOrderFields.DueDay);
fieldList.Add(SalesOrderFields.OrdreNo);
SalesOrderEntity sales=adapter.FetchEntity(salesOrder, prefetchPath, null, fieldList);
然后会应用读到的值DueDay和OrdreNo,如果SalesOrderEntity还有一个字段是SalesMan(string,varchar(50)),
在这种读取模式下,这个值永远是string.Empty.

转载地址:http://awgzz.baihongyu.com/

你可能感兴趣的文章
JVM基础系列第11讲:JVM参数之堆栈空间配置
查看>>
MySQL用户管理:添加用户、授权、删除用户
查看>>
比技术还重要的事
查看>>
linux线程调度策略
查看>>
软中断和实时性
查看>>
Linux探测工具BCC(可观测性)
查看>>
Opentelemetry Metrics SDK
查看>>
流量控制--2.传统的流量控制元素
查看>>
SNMP介绍及使用,超有用,建议收藏!
查看>>
SDUT2161:Simple Game(NIM博弈+巴什博弈)
查看>>
51nod 1596 搬货物(二进制处理)
查看>>
来自星星的祝福(容斥+排列组合)
查看>>
Hmz 的女装(递推)
查看>>
HDU5589:Tree(莫队+01字典树)
查看>>
Codeforces Round #459 (Div. 2):D. MADMAX(记忆化搜索+博弈论)
查看>>
不停机替换线上代码? 你没听错,Arthas它能做到
查看>>
sharding-jdbc 分库分表的 4种分片策略,还蛮简单的
查看>>
分库分表的 9种分布式主键ID 生成方案,挺全乎的
查看>>
MySQL不会丢失数据的秘密,就藏在它的 7种日志里
查看>>
Python开发之序列化与反序列化:pickle、json模块使用详解
查看>>