更新:2007 年 11 月
在 Visual Studio Team System Database Edition 中,您可以在自定义数据生成器类中创建标准数据生成器类的实例。使用此方法,您可以轻松地减少自定义数据生成器中必需包括的逻辑的数量。例如,您可能希望创建一个可以生成与多个复杂模式相匹配的随机字符串数据的生成器。您可以创建一个包含处理多个模式的逻辑的自定义数据生成器,还可以使用标准 RegularExpression 生成器来处理复杂的模式匹配。
在本演练中,您将创建一个聚合标准 DateTime 生成器的自定义数据生成器。该生成器所生成的数据将位于两个不同的日期范围中的一个范围之内。该生成器接受两个不同的范围作为其输入,并生成一个位于其中一个范围内的随机日期。
![]() |
---|
有关该自定义数据生成器的目标的更多信息以及如何使用常规扩展性来实现同样的目标,请参见演练:为 CHECK 约束创建自定义数据生成器。 |
在本演练中,您将执行下列任务:
创建从 Generator 继承的类。
创建输入属性,以便用户可以指定两个日期范围。
创建要用作生成器输出的输出属性。
创建两个标准 DateTime 生成器实例,它们分别代表两个可能的范围中的一个。
重写 Generator 方法,并在这些方法内将工作委托给标准生成器。
用强名称对生成器进行签名。
先决条件
若要完成此演练,需要以下组件:
- Database Edition
创建自定义数据生成器类
创建自定义数据生成器类
在 Visual Studio 中,用所选语言创建一个类库项目并将它命名为“GeneratorDateRanges2”。
在“项目”菜单上单击“添加引用”。
随即出现“添加引用”对话框。
单击“.NET”选项卡。在“组件名称”列表中,单击“Microsoft.VisualStudio.TeamSystem.Data”,再单击“确定”。
在“项目”菜单上单击“添加引用”。
随即出现“添加引用”对话框。
单击“浏览”选项卡,然后浏览至如下位置:...\Program Files\Microsoft Visual Studio 9.0\DBPro\Extensions。
单击“Microsoft.VisualStudio.TeamSystem.Data.Generators.dll”,再单击“确定”。
(可选,仅限 Visual Basic)在“解决方案资源管理器”中,单击“显示所有文件”,再展开“引用”节点以验证新引用。
在“代码”窗口顶部的类声明之前,添加下面的代码行:
Imports Microsoft.VisualStudio.TeamSystem.Data.DataGenerator Imports Microsoft.VisualStudio.TeamSystem.Data.Generators Imports System.Data.SqlTypes
using Microsoft.VisualStudio.TeamSystem.Data.DataGenerator; using Microsoft.VisualStudio.TeamSystem.Data.Generators; using System.Data.SqlTypes;
将该类从 Class1 重命名为 GeneratorDateRanges2,并指定该类从 Generator 继承,如下面的示例所示。
警告:
默认情况下,为该类指定的名称将显示在“列详细信息”窗口上的“生成器”列中。所指定的名称不应当与标准生成器或其他自定义生成器的名称冲突。
Public Class GeneratorDateRanges2 Inherits Generator End Class
public class GeneratorDateRanges2: Generator { }
在“文件”菜单上,单击“全部保存”。
添加输入属性
这个自定义数据生成器接受两个日期范围作为其输入。若要指定每个范围,用户需要分别为每个范围指定最小日期和最大日期。因此,共需创建四个输入属性:两个最小日期和两个最大日期。
添加输入属性
创建四个成员变量来存放这两个日期范围的最小日期和最大日期,如下面的示例所示。
Dim range1MinValue As SqlDateTime Dim range1MaxValue As SqlDateTime Dim range2MinValue As SqlDateTime Dim range2MaxValue As SqlDateTime
SqlDateTime range1MinValue; SqlDateTime range1MaxValue; SqlDateTime range2MinValue; SqlDateTime range2MaxValue;
创建四个属性来设置这两个日期范围的最小日期和最大日期,如下面的示例所示。这些属性必须具有 InputAttribute 才能被识别为输入属性。
<Input(Visible:= true, TypeConverter:= GetType(SqlDateTimeConverter))> _ Public Property Range1Min() As SqlDateTime Set(ByVal value As SqlDateTime) range1MinValue = value End Set Get Return range1MinValue End Get End Property <Input(Visible:= true, TypeConverter:= GetType(SqlDateTimeConverter))> _ Public Property Range1Max() As SqlDateTime Set(ByVal value As SqlDateTime) range1MaxValue = value End Set Get Return range1MaxValue End Get End Property <Input(Visible:= true, TypeConverter:= GetType(SqlDateTimeConverter))> _ Public Property Range2Min() As SqlDateTime Set(ByVal value As SqlDateTime) range2MinValue = value End Set Get Return range2MinValue End Get End Property <Input(Visible:= true, TypeConverter:= GetType(SqlDateTimeConverter))> _ Public Property Range2Max() As SqlDateTime Set(ByVal value As SqlDateTime) range2MaxValue = value End Set Get Return range2MaxValue End Get End Property
[Input(Visible = true, TypeConverter = typeof(SqlDateTimeConverter))] public SqlDateTime Range1Min { set {range1MinValue = value;} get {return range1MinValue;} } [Input(Visible = true, TypeConverter = typeof(SqlDateTimeConverter))] public SqlDateTime Range1Max { set {range1MaxValue = value;} get {return range1MaxValue;} } [Input(Visible = true, TypeConverter = typeof(SqlDateTimeConverter))] public SqlDateTime Range2Min { set {range2MinValue = value;} get {return range2MinValue;} } [Input(Visible = true, TypeConverter = typeof(SqlDateTimeConverter))] public SqlDateTime Range2Max { set {range2MaxValue = value;} get {return range2MaxValue;} }
在“文件”菜单上,单击“全部保存”。
添加输出属性
这个自定义数据生成器会返回一个随机日期作为其输出。因此,必须创建一个输出属性。
添加输出属性
创建一个成员变量来存放作为输出的随机日期,如下面的示例所示。
Dim randomDateValue As SqlDateTime
SqlDateTime randomDateValue;
创建一个属性来返回作为输出的随机日期,如下面的示例所示。该属性必须具有 OutputAttribute 才能被识别为输出属性。
<Output()> _ Public ReadOnly Property RandomDate() As SqlDateTime Get Return randomDateValue End Get End Property
[Output] public SqlDateTime RandomDate { get {return randomDateValue;} }
在“文件”菜单上单击“全部保存”。
重写 OnInitialize 方法
重写 OnInitialize 方法
创建一个成员变量来生成随机数,如下面的示例所示。该变量用来在两个可能的日期范围之间随机选择。
Dim randomRange As Random
Random randomRange;
创建并实例化作为标准的 DateTime 生成器的两个成员变量,如下面的示例所示。
Dim range1 As DatabaseDateTime = New DatabaseDateTime() Dim range2 As DatabaseDateTime = New DatabaseDateTime()
DatabaseDateTime range1 = new DatabaseDateTime(); DatabaseDateTime range2 = new DatabaseDateTime();
重写 OnInitialize 方法,如下面的示例所示。在该方法中,为 Random 对象提供种子并使生成器具有确定性。还可以调用标准生成器的 Initialize 方法。
Protected Overrides Sub OnInitialize(ByVal initInfo As GeneratorInit) randomRange = New Random(Me.Seed) 'deterministic range1.Initialize(initInfo) range2.Initialize(initInfo) MyBase.OnInitialize(initInfo) End Sub
protected override void OnInitialize(GeneratorInit initInfo) { randomRange = new Random(this.Seed); //deterministic range1.Initialize(initInfo); range2.Initialize(initInfo); base.OnInitialize(initInfo); }
在“文件”菜单上,单击“全部保存”。
重写其他方法
重写其他方法
重写 OnSetInputValues,如下面的示例所示。此方法的 inputs 参数是由用户设置的所有标准生成器属性(如“种子”和“Null 百分比”)的 IDictionary。您调用标准生成器的 SetInputValues 方法,以便将这些值传递给它们。然后,使用在该数据生成器中创建的自定义输入属性来设置每个标准生成器的 Min 和 Max 属性。
Protected Overrides Sub OnSetInputValues(ByVal inputs As IDictionary(Of String, Object)) 'It is important to call MyBase.OnSetInputValues first to get the inputs 'from the Properties window first. '-------------------------------------------------------------------------- MyBase.OnSetInputValues(inputs) range1.SetInputValues(inputs) range2.SetInputValues(inputs) range1.Min = range1MinValue range1.Max = range1MaxValue range2.Min = range2MinValue range2.Max = range2MaxValue range1.Distribution = New Uniform() range2.Distribution = New Uniform() End Sub
protected override void OnSetInputValues(IDictionary<string, object> inputs) { //It is important to call base.OnSetInputValues first to get the inputs //from the Properties window first. //------------------------------------------------------------------------- base.OnSetInputValues(inputs); range1.SetInputValues(inputs); range2.SetInputValues(inputs); range1.Min = range1MinValue; range1.Max = range1MaxValue; range2.Min = range2MinValue; range2.Max = range2MaxValue; range1.Distribution = new Uniform(); range2.Distribution = new Uniform(); }
重写 OnValidateInputs 以验证输入,如下面的示例所示。
Protected Overrides Sub OnValidateInputs() range1.ValidateInputs() range2.ValidateInputs() MyBase.OnValidateInputs() End Sub
protected override void OnValidateInputs() { range1.ValidateInputs(); range2.ValidateInputs(); base.OnValidateInputs(); }
重写 Dispose(Boolean) 方法以清理标准生成器,如下面的示例所示。
Protected Overrides Sub Dispose(ByVal disposing As Boolean) range1.Dispose() range2.Dispose() MyBase.Dispose(disposing) End Sub
protected override void Dispose(bool disposing) { range1.Dispose(); range2.Dispose(); base.Dispose(disposing); }
在“文件”菜单上单击“全部保存”。
重写 OnGenerateNextValues 方法
Database Edition 调用生成器的 OnGenerateNextValues 方法来创建它需要的数据。必须重写此方法来提供为输出属性生成随机日期的逻辑。在本演练中,您将生成随机日期的职责委托给标准 DateTime 生成器。
重写 OnGenerateNextValues 方法
重写 OnGenerateNextValues 方法,如下面的示例所示。
Protected Overrides Sub OnGenerateNextValues() 'Generate a random date from either range 1 or range 2. 'Randomly select either range 1 or range 2 by randomly 'generating an odd or an even random number. '------------------------------------------------------------ If (randomRange.Next() Mod 2 = 0) Then 'check for odd or even 'the standard generator does the work range1.GenerateNextValues() randomDateValue = range1.Result.Value Else 'the standard generator does the work range2.GenerateNextValues() randomDateValue = range2.Result.Value End If MyBase.OnGenerateNextValues() End Sub
protected override void OnGenerateNextValues() { //Generate a random date from either range 1 or range 2. //Randomly select either range 1 or range 2 by randomly //generating an odd or an even random number. //------------------------------------------------------------ if (randomRange.Next() % 2 == 0) //check for odd or even { //the standard generator does the work range1.GenerateNextValues(); randomDateValue = range1.Result.Value; } else { //the standard generator does the work range2.GenerateNextValues(); randomDateValue = range2.Result.Value; } base.OnGenerateNextValues(); }
在“文件”菜单上单击“全部保存”。
定义类型转换器
若要在“属性”窗口中为该数据生成器指定输入属性,必须提供一个用来在输入值和 SqlDateTime 类型之间来回转换的类型转换器。
创建 SqlDateTime 类型转换器类
在“项目”菜单上单击“添加类”。
即会出现“添加新项”对话框。
在“名称”中键入 SqlDateTimeConverter。
在“代码”窗口顶部的类声明之前,添加下面的代码行:
Imports System.ComponentModel Imports System.Data.SqlTypes Imports System.Globalization
using System.ComponentModel; using System.Data.SqlTypes; using System.Globalization;
将该类从 Class1 重命名为 GeneratorDateRanges,并指定该类从 TypeConverter 继承。
Public Class SqlDateTimeConverter Inherits TypeConverter End Class
public class SqlDateTimeConverter: TypeConverter { }
在类声明内部添加类构造函数。如果是在 Visual Basic 中编写类型转换器类,请跳至步骤 6。
public SqlDateTimeConverter() { }
在类构造函数之后,添加一个方法来验证该类型转换器是否可以实现特定的转换。
Public Overrides Function CanConvertFrom(ByVal context As ITypeDescriptorContext, ByVal sourceType As Type) As Boolean Dim result As Boolean result = False If (sourceType Is GetType(System.String)) Then result = True Else result = MyBase.CanConvertFrom(context, sourceType) End If Return result End Function
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { bool result = false; if (sourceType == typeof(string)) { result = true; } else { result = base.CanConvertFrom(context, sourceType); } return result; }
最后添加转换器方法。
Public Overrides Function ConvertFrom(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal culture As System.Globalization.CultureInfo, ByVal value As Object) As Object Dim dateTimeString As String dateTimeString = value.ToString If (dateTimeString.Length > 0) Then Dim dateTime As Date dateTime = Date.Parse(dateTimeString, culture) Return New SqlDateTime(dateTime) End If Return MyBase.ConvertFrom(context, culture, value) End Function Public Overrides Function CanConvertTo(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal destinationType As System.Type) As Boolean If (destinationType Is GetType(System.String)) Then Return True End If Return MyBase.CanConvertTo(context, destinationType) End Function Public Overrides Function ConvertTo(ByVal context As System.ComponentModel.ITypeDescriptorContext, ByVal culture As System.Globalization.CultureInfo, ByVal value As Object, ByVal destinationType As System.Type) As Object If (destinationType Is GetType(System.String)) Then Dim dateTime As Date dateTime = CType(value, SqlDateTime).Value dateTime.ToString(culture) End If Return MyBase.ConvertTo(context, culture, value, destinationType) End Function
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { string dateTimeString = value as string; if (dateTimeString != null) { DateTime dateTime = DateTime.Parse(dateTimeString, culture); return new SqlDateTime(dateTime); } return base.ConvertFrom(context, culture, value); } public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { if (destinationType == typeof(string)) { return true; } return base.CanConvertTo(context, destinationType); } public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string)) { DateTime dateTime = ((SqlDateTime)value).Value; dateTime.ToString(culture); } return base.ConvertTo(context, culture, value, destinationType); }
在“文件”菜单上单击“全部保存”。
对生成器进行签名
所有的自定义数据生成器都必须先使用强名称进行签名才能注册。
使用强名称对生成器进行签名
在“项目”菜单上,单击“GeneratorDateRanges2 属性”打开项目属性。
在“签名”选项卡上,选中“为程序集签名”复选框。
在“选择强名称密钥文件”框中,单击“<新建...>”。
在“密钥文件名称”框中,键入“GeneratorDateRanges2Key”,键入并确认密码,然后单击“确定”。
在生成解决方案时,将使用密钥文件对程序集进行签名。
在“文件”菜单上单击“全部保存”。
在“生成”菜单上,单击“生成解决方案”。
现在已经生成了数据生成器。接下来您必须在自己的计算机上注册它,以便可以在数据生成计划中使用它。
安全性
有关更多信息,请参见数据生成器的安全性。
后续步骤
现在已经生成了数据生成器,接下来您必须在自己的计算机上注册它。有关更多信息,请参见下列主题之一:
请参见
任务
概念
参考
Microsoft.VisualStudio.TeamSystem.Data.DataGenerator