InvalidRegionIsInactiveButOfficeIsActiveView视图

  业务规则是如果区域(Region)是不活动的,不能存在活动的办事处(Office)与其关联。换句话说,不能在属于某个区域的办事处还是active的情况下关闭这个区域,除非设置IsActive为0或是将这个办事处分到其它区域(Region),下面的View显示了显示了Region的IsActive为0并且属于它的offce的IsActive为1的例子。这违背了预设的业务规则.与dbo.DuplicateRows进行Cross Join是为了实现如果Where子句满足条件,少返回两行。

CREATE View dbo.InvalidRegionIsInactiveButOfficeIsActiveView With SchemaBinding

As

SELECT     dbo.Region.RegionId
FROM       dbo.Region
INNER JOIN dbo.Office
ON         dbo.Region.RegionId = dbo.Office.RegionId
CROSS JOIN dbo.DuplicateRows
WHERE      dbo.Region.IsActive = Convert(bit, 0)
AND        dbo.Office.IsActive = Convert(bit, 1)
 


  后的画龙点睛之笔是创建索引,索引是为了防止重复行,但是这个视图与一个两行的表进行Cross Join,这使得如果要返回结果,则返回一个两行的结果。但这又违背了索引,所以这种情况永远不可能发生。

CREATE UNIQUE CLUSTERED INDEX IX_RegionInvalidOfficeIsActiveView_RegionId ON dbo.InvalidRegionIsInactiveButOfficeIsActiveView
 (RegionId ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]


  后的结果是不会违背业务规则。

  测试:关闭Antarctica区域

  总部的那帮家伙决定关闭Antarctica区域。下面语句在不顾与之关联的Office的状态的情况下设置Region的IsActive为0。

UPDATE dbo.Region
 SET dbo.Region.IsActive  = Convert(bit, 0),
     dbo.Region.ExpirationDate = GetDate()
 WHERE dbo.Region.RegionName  = N'Antarctica'


  当执行后,发生如下错误:

Msg 2601, Level 14, State 1, Line 1
Cannot insert duplicate key row in object 'dbo.InvalidRegionIsInactiveButOfficeIsActiveView' with unique index 'IX_RegionInvalidOfficeIsActiveView_RegionId'. The duplicate key value is (5).


  在关闭Antarctica区域之前,Byrd Station办事处必须设置成不活动的或者是分配给其它区域,因为我并不想解雇这个办事处的任何人,所以我将这个办事处分为了其它区域。

UPDATE dbo.Office
 SET dbo.Office.RegionId = (SELECT dbo.Region.Regionid
                             FROM dbo.Region
                             WHERE dbo.Region.RegionName = N'South'
                            )
 FROM dbo.Office
 WHERE dbo.Office.RegionId =(SELECT dbo.Region.Regionid
                              FROM dbo.Region
                              WHERE dbo.Region.RegionName = N'Antarctica'
                             )


  一旦没有任何活动的办事处与Antarctica区域相关联,我可以通过Update语句来关闭Antarctica区域了。

  如何在你的数据库中实现这个技巧

  下面几部帮助你在数据库中实现这个技巧:

  1、创建dbo.DuplicateRows table表并插入两条数据

  2、写一个违反了业务规则并且还能返回结果的查询

  3、在这个查询中与dbo.DuplicateRows进行Cross Join

  4、创建一个包含SchemaBinding参数和上面查询语句的视图

  5、在视图上创建索引

  总结

  使用索引视图和一个两行的表进行连接或许并不是实现业务规则有效的手段,但是使用了这种方法可以避免使用复杂的Instead of触发器。假如微软提供了“Before触发器”使得违反业务规则的查询在执行之前被取消的话,不需要我这种手段了。上面的技巧可以看作是一个无奈的人实现的山寨版”before 触发器”。