为什么会出错?因为只有当父列存在一致性约束时,才允许在列表达式中使用 Child 关键字。这一点在开发文档中并未明确指出,然而它却是事实,而且非常重要。令人不解的是,你不但可以顺利地访问 Orders 表任一行的子元素,还能直接访问 Employees 表或 Customers 表的任一列。以下代码可以证明这一点:
Dim orders As DataTable = ds.Tables("Orders") Dim employee As DataRow = orders.Rows(0).GetChildRows(relOrder2Employees) MsgBox employee("lastname")
因此,所谓的“句法错误”,并不代表你无法建立多对一关系。它只是提醒你:除非事先建立一致性约束,否则就不能在列表达式中使用 Child 关键字。
在初始关系中,Orders 表是父表。然而,为了从 ID 获取提交者名字或客户公司名,你就必须改变诸表所扮演的角色:让 Orders 表充当子表,而让 Employees 表、Customers 表充当父表。为了确保做到这一点,你必须改变 DataRelation 对象构造器代码中的列名,并且象这样使用列表达式:
Dim orders As DataTable = ds.Tables("Orders") orders.Columns.Add("Employee", GetType(String), _ "Parent(Orders2Employees).lastname") orders.Columns.Add("Customer", GetType(String), _ "Parent(Orders2Customers).companyname")
小结:在本例中,我们把一个复杂的 SQL 查询分解成 3 个较为简单的子查询,从而消除了两个 INNER JOIN 语句,减轻了数据库服务器的负担;更重要的是,大大减少了从服务器到客户端的网络传输负荷。看来,这似乎是最好的解决方案了?
替代方案
前面的解决方案是以对照表为基础的,而且在对照表的生成过程中没有进行数据过滤。一旦对照表的规模过大,会有什么后果呢?难道你愿意为了得到区区数百个提交者的名字就从服务器下载 10,000 条记录?难道你甘心下载那一大堆冗余数据?更何况,那些冗余数据对你毫无用处!
可是,请换个角度想一想。对照表在应用程序的整个生命周期中往往都是有价值的。也换言之,虽然对单独一次查询来说,下载许多记录以构建完整的对照表未免过于奢侈,但是它对整个应用程序来说也未必不是公平交易。
既然这样,我们何不尝试用另一种技术来缩减对照表的规模呢?最容易想到的方案莫过于借助 WHERE 子句来缩小结果集了。非常不幸,此方案要么难以实现,要么效果欠佳,尤其是在对照表诸列并不包括你所要查询的对象时。例如:为了对提交者的名字进行过滤,你就必须对其它表进行联合查询——比如 Order 表和 Order Details(订单细节) 表。我认为,最佳方案是重新获取上次 SQL 查询的返回结果集,并从中解析出每个提交者的信息。也就是说,完成前述 SQL 查询之后,再次发送一个几乎相同的查询命令,令数据库服务器重新运行分解后的子查询。这样,数据库将以最小的查询代价返回完全相同的数据。更妙的是,SQL 服务器还特别设置了查询优化引擎,使得此类重复查询的代价减到最低。
SELECT DISTINCT t.customerid, t.companyname FROM (SELECT o.customerid, o.orderid, o.orderdate, o.shippeddate, SUM(od.quantity*od.unitprice) AS price, c.companyname, o.employeeid FROM orders AS o INNER JOIN Customers AS c ON c.customerid=o.customerid INNER JOIN [Order Details] AS od ON o.orderid=od.orderid WHERE Year(o.orderdate) = @TheYear AND od.orderid=o.orderid GROUP BY o.customerid, o.orderid, c.companyname, o.orderdate, o.shippeddate, o.employeeid HAVING SUM(od.quantity) >30) AS t
总而言之,以若干简单查询为基础而设计的资料检索代码最大的优点是:它把数据联结 (joining) 的重任由服务器转移到了客户端。另一方面,由于客户端把数据记录分布于几个相互独立、易于链接的表内,因而数据查询操作异常灵活。
用一些短小、简单的 SQL 查询从数据库读取记录并分别保存到额外的DataTable 对象中,这对客户端应用程序来说是一个好消息。可是,如果这些子查询返回的部分数据不符合一致性约束,那又会如何呢?
事务的应用
通常,每个查询命令,无论它有多复杂,都是在同一个默认的事务(transaction)中执行的。正因为如此,它才能确保在执行过程中不会因为其它代码的干扰而破坏数据的整体一致性。可是,假如你把作为逻辑整体的查询命令分解成为若干子查询,结果又会怎么样?
上一页 [1] [2] [3] [4] [5] [6] 下一页
|