演练:为 CHECK 约束创建自定义数据生成器
更新:2007 年 11 月
在 Visual Studio Team System Database Edition 中,可以使用标准数据生成器在列中填充数据。如果要填充的列已定义了一个 CHECK 约束,则填充该列的数据必须满足该 CHECK 约束。标准数据生成器可以生成满足许多 CHECK 约束的数据。例如,如果您有一个要求日期位于某个范围内的 CHECK 约束,则您可以使用标准 DateTime 生成器并设置 Min 和 Max 属性来满足该 CHECK 约束。
但是,标准数据生成器并不能满足所有的 CHECK 约束。例如,如果 CHECK 约束要求日期位于两个不同范围中的任一范围内,则不能使用标准 DateTime 生成器。在本演练中,您将创建一个能够满足这种约束的自定义数据生成器。该生成器接受两个范围作为其输入,并生成一个位于其中一个范围内的随机日期。
说明: |
---|
您可以通过其他方法来创建自定义数据生成器,并使用聚合扩展性来实现同样的目标。有关更多信息,请参见演练:创建聚合标准生成器的自定义数据生成器。 |
在本演练中,您将执行下列任务:
创建从 Generator 继承的类。
创建输入属性,以便用户可以指定两个日期范围。
创建要用作生成器输出的输出属性。
重写 OnInitialize 方法,以便为 Random 对象提供种子并使生成器具有确定性。
重写 OnGenerateNextValues 方法以生成数据。
用强名称对生成器进行签名。
先决条件
若要完成此演练,需要以下组件:
- Database Edition
创建自定义数据生成器类
创建自定义数据生成器类
在 Visual Studio 中,用所选语言创建一个类库项目并将它命名为“GeneratorDateRanges”。
在“项目”菜单上单击“添加引用”。
随即出现“添加引用”对话框。
单击“.NET”选项卡。在“组件名称”列表中,单击“Microsoft.VisualStudio.TeamSystem.Data”,再单击“确定”。
(可选,仅限 Visual Basic)在“解决方案资源管理器”中,单击“显示所有文件”,再展开“引用”节点以验证新引用。
在“代码”窗口顶部的类声明之前,添加下面的代码行:
Imports Microsoft.VisualStudio.TeamSystem.Data.DataGenerator Imports System.Data.SqlTypes
using Microsoft.VisualStudio.TeamSystem.Data.DataGenerator; using System.Data.SqlTypes;
将该类从 Class1 重命名为 GeneratorDateRanges,并指定该类从 Generator 继承。
警告: 默认情况下,为该类指定的名称将显示在“列详细信息”窗口上的“生成器”列中。所指定的名称不应当与标准生成器或其他自定义生成器的名称冲突。
Public Class GeneratorDateRanges Inherits Generator End Class
public class GeneratorDateRanges: 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(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(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(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(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(TypeConverter = typeof(SqlDateTimeConverter))] public SqlDateTime Range1Min { set {range1MinValue = value;} get {return range1MinValue;} } [Input(TypeConverter = typeof(SqlDateTimeConverter))] public SqlDateTime Range1Max { set {range1MaxValue = value;} get {return range1MaxValue;} } [Input(TypeConverter = typeof(SqlDateTimeConverter))] public SqlDateTime Range2Min { set {range2MinValue = value;} get {return range2MinValue;} } [Input(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 方法
生成随机数据时,数据可以是确定性的,也可以是非确定性的。每次从同一个种子生成的确定性数据都是相同的。所有的数据生成器都有一个可以由用户设置的 Seed 属性。可以重写 OnInitialize 方法,以便为 Random 对象提供种子并使生成器具有确定性。
重写 OnInitialize 方法
创建两个成员变量来生成随机数,如下面的示例所示。一个变量用来生成随机日期。另一个变量用来在两个可能的日期范围之间随机选择。
Dim random As Random Dim randomRange As Random
Random random; Random randomRange;
重写 OnInitialize 方法。
Protected Overrides Sub OnInitialize(ByVal initInfo As GeneratorInit) random = New Random(Me.Seed) 'deterministic randomRange = New Random(Me.Seed) 'deterministic 'random = New Random() 'non-deterministic 'randomRange = New Random() 'non-deterministic MyBase.OnInitialize(initInfo) End Sub
protected override void OnInitialize(GeneratorInit initInfo) { random = new Random(this.Seed); //deterministic randomRange = new Random(this.Seed); //deterministic //random = new Random(); //non-deterministic //randomRange = new Random(); //non-deterministic base.OnInitialize(initInfo); }
在“文件”菜单上单击“全部保存”。
重写 OnGenerateNextValues 方法
Database Edition 调用生成器的 OnGenerateNextValues 方法来创建它需要的数据。您必须重写此方法,才能为输出属性提供用于生成随机日期的逻辑。
重写 OnGenerateNextValues 方法
重写 OnGenerateNextValues 方法,如下面的示例所示。
Protected Overrides Sub OnGenerateNextValues() Dim min As SqlDateTime Dim max As SqlDateTime '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 min = range1MinValue max = range1MaxValue Else min = range2MinValue max = range2MaxValue End If 'The formula for creating a random number in a specific range is: 'start of range + (size of range * random number between 0 and 1) 'size of range Dim range As TimeSpan = max.Value - min.Value '(size of range * random number between 0 and 1) Dim randomNumber As TimeSpan = New TimeSpan(CLng(range.Ticks * random.NextDouble())) 'start of range + (size of range * random number between 0 and 1) randomDateValue = min + randomNumber End Sub
protected override void OnGenerateNextValues() { SqlDateTime min; SqlDateTime max; //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 { min = range1MinValue; max = range1MaxValue; } else { min = range2MinValue; max = range2MaxValue; } //The formula for creating a random number in a specific range is: //start of range + (size of range * random number between 0 and 1) //size of range TimeSpan range = max.Value - min.Value; //(size of range * random number between 0 and 1) TimeSpan randomNumber = new TimeSpan((long)(range.Ticks * random.NextDouble())); //start of range + (size of range * random number between 0 and 1) randomDateValue = min + randomNumber; }
在“文件”菜单上单击“全部保存”。
定义类型转换器
为了在属性浏览器中针对该数据生成器指定输入属性,必须提供一个用来在输入值和 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 继承。
[Visual Basic] 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 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 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 override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { if (destinationType == typeof(string)) { return true; } return base.CanConvertTo(context, destinationType); }
最后添加转换器方法。
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 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 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); }
在“文件”菜单上单击“全部保存”。
对生成器进行签名
所有的自定义数据生成器都必须先使用强名称进行签名才能注册。
使用强名称对生成器进行签名
在“项目”菜单上,单击“GeneratorDateRanges 属性”打开项目属性。
在“签名”选项卡上,选中“为程序集签名”复选框。
在“选择强名称密钥文件”框中,单击“<新建...>”。
在“密钥文件名称”框中,键入“GeneratorDateRangesKey”,键入并确认密码,然后单击“确定”。
在生成解决方案时,将使用密钥文件对程序集进行签名。
在“文件”菜单上单击“全部保存”。
在“生成”菜单上,单击“生成解决方案”。
现在已经生成了数据生成器。接下来您必须在自己的计算机上注册它,以便可以在数据生成计划中使用它。
安全性
有关更多信息,请参见数据生成器的安全性。
后续步骤
现在已经生成了数据生成器,接下来您必须在自己的计算机上注册它。有关更多信息,请参见下列主题之一:
请参见
任务
概念
参考
Microsoft.VisualStudio.TeamSystem.Data.DataGenerator