这里我们来一步步阐明这些部门的寄义,这个内里DataMapper主要是用来界说一些C#基本数据范例和数据库生成剧本之间的映射干系。
1 GetTableName接下来我们看看GetTableName这个函数,这里首先来当前Model是否界说了TempTableAttribute,这个看名字就清楚了就是用来界说当前Model是否是用来生成一张姑且表的。
/// <summary> /// 是否姑且表, 仅限 Dapper 生成 数据库表布局时利用 /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] public class TempTableAttribute : Attribute { }
详细我们来看看奈何在实体Model中界说TempTableAttribute这个自界说属性。
[TempTable] class StringTable { public string DefaultString { get; set; } [MaxLength(30)] public string LengthString { get; set; } [Required] public string NotNullString { get; set; } }
就像这样界说的话,我们就知道当前Model会生成一张SQL Server的姑且表。
虽然假如是生成姑且表,则会在生成的表名称前面加一个‘#'符号,在这段代码中我们还会去判定当前实体是否界说了TableAttribute,假如界说过就去取这个TableAttribute的名称,不然就去当前Model的名称,这里也举一个实例。
[Table("Test")] class IntTable { public int IntProperty { get; set; } public int? NullableIntProperty { get; set; } }
这样我们通过代码建设的数据库名称就是Test啦。
2 GenerateFields这个主要是用来一个个读取Model中的属性,并将每一个实体属性整理成一个KeyValuePair<string, PropertyInfo>的工具从而利便最后一步来生成整个表完整的剧本,这里也有些内容需要留意,假如当前属性界说了NotMappedAttribute标签,那么我们可以直接跳过当前属性,别的还需要留意的处所就是当前属性的名称首先看当前属性是否界说了ColumnAttribute的假如界说了,那么数据库中字段名称就取自ColumnAttribute界说的名称,不然才是取自当前属性的名称,通过这样一步操纵我们就可以或许将所有的属性读取到一个自界说的数据布局List<KeyValuePair<string, PropertyInfo>>内里去了。
3 GenerateTableScript有了前面的两步筹备事情,后头就是进入到生成整个建设表剧本的部门了,其实这里也较量简朴,就是通过轮回来一个个生成每一个属性对应的剧本,然后通过StringBuilder来拼接到一起形成一个完整的整体。这内里有一点需要我们留意的处所就是当前字段是否可为空还取决于当前属性是否界说过RequiredAttribute标签,假如界说过那么就需要在建设的剧本后头添加Not Null,最后一个重点就是对付string范例的属性我们需要读取其界说的MaxLength属性从而确定命据库中的字段长度,假如没有界说则取默认长度500。
虽然一个完整的代码怎么能少得了单位测试呢?下面我们来看看单位测试。
二 单位测试public class SqlServerTableGenerator_Tests { [Table("Test")] class IntTable { public int IntProperty { get; set; } public int? NullableIntProperty { get; set; } } [Fact] public void GenerateTableScript_Int_Number10() { // Act var sql = new TableGenerator().GenerateTableScript(typeof(IntTable)); // Assert sql.ShouldContain("IntProperty NUMBER(10) NOT NULL"); sql.ShouldContain("NullableIntProperty NUMBER(10)"); } [Fact] public void GenerateTableScript_TestTableName_Test() { // Act var sql = new TableGenerator().GenerateTableScript(typeof(IntTable)); // Assert sql.ShouldContain("CREATE TABLE Test"); } [TempTable] class StringTable { public string DefaultString { get; set; } [MaxLength(30)] public string LengthString { get; set; } [Required] public string NotNullString { get; set; } } [Fact] public void GenerateTableScript_TempTable_TableNameWithSharp() { // Act var sql = new TableGenerator().GenerateTableScript(typeof(StringTable)); // Assert sql.ShouldContain("Create Table #StringTable"); } [Fact] public void GenerateTableScript_String_Varchar() { // Act var sql = new TableGenerator().GenerateTableScript(typeof(StringTable)); // Assert sql.ShouldContain("DefaultString VARCHAR2(500 CHAR)"); sql.ShouldContain("LengthString VARCHAR2(30 CHAR)"); sql.ShouldContain("NotNullString VARCHAR2(500 CHAR) NOT NULL"); } class ColumnTable { [Column("Test")] public int IntProperty { get; set; } [NotMapped] public int Ingored {get; set; } } [Fact] public void GenerateTableScript_ColumnName_NewName() { // Act var sql = new TableGenerator().GenerateTableScript(typeof(ColumnTable)); // Assert sql.ShouldContain("Test NUMBER(10) NOT NULL"); } [Fact] public void GenerateTableScript_NotMapped_Ignore() { // Act var sql = new TableGenerator().GenerateTableScript(typeof(ColumnTable)); // Assert sql.ShouldNotContain("Ingored NUMBER(10) NOT NULL"); } class NotSupportedTable { public dynamic Ingored {get; set; } } [Fact] public void GenerateTableScript_NotSupported_ThrowException() { // Act Assert.Throws<NotSupportedException>(() => { new TableGenerator().GenerateTableScript(typeof(NotSupportedTable)); }); } }
最后我们来看看最终生成的建设表的剧本。
1 界说过TableAttribute的剧本。