在我看来,最简单的方法是通过使用安全性来确定用户获取哪个页面的页面集合来分离功能。除了安全性和其他确保用户无法直接访问他们没有权限的页面的手段(例如站点地图等),您还可以在数据库中存储功能列表以及具有访问该功能的用户或角色:
Create Table Features
(
Code varchar(10) not null Primary Key
, StartPage nvarchar(max) not null
, Description nvarchar(max) not null
)
Create Table UserFeatures
(
UserId ... not null
, FeatureCode varchar(10) References Features ( Code )
)
首先,我使用文本代码作为特征主键而不是像IDENTITY列或GUID这样的代理键的原因是只有系统会查询特征。用户永远不会有任意添加特征的能力。因此,查询
...Where FeatureCode = 'AdvancedEntry'
比查询
...Where FeatureId = 13
使您的代码更清晰、更易于阅读。
其次,在这种方法中,页面本身的代码将确定调用哪个过程。然而,如果这些特性仅涉及附加信息字段,则可能意味着相当多的重复。
因此,如果这些特性与现有代码库和表示层紧密集成(这也是版本控制如此困难的原因),另一种方法是在
Features
表中存储应该使用的存储过程的名称。您的代码将查询连接上述表并返回应该使用的存储过程名称。对于参数,您可以在数据库中存储参数化调用(例如
exec Schema.Foo @bar, @gamma, @beta
),并在执行查询时简单地检查该字符串是否包含给定参数,如果包含,则添加该参数值:
if ( ProcTemplate.Contains( "@bar")
commandInstance.Parameters.AddWithValue( "@bar", barValue );
if ( ProcTemplate.Contains( "@gamma")
commandInstance.Parameters.AddWithValue( "@gamma", gammaValue );
...
如果您将功能映射到用户角色或组,则需要制定“优先”规则,以确定在返回多个功能的情况下应使用哪个功能。在这种方法中,您将保留现有的存储过程,除非模式需要更改存储过程(例如,删除列)。此方法的额外结果是,您可以向
Features
表添加日期,以确定何时应上线新功能。