国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - ASP.NET教程 - EFCore 通過實體Model生成創建SQL Server數據庫表腳本

EFCore 通過實體Model生成創建SQL Server數據庫表腳本

2021-12-08 15:25Hello——尋夢者! ASP.NET教程

這篇文章主要介紹了EFCore 通過實體Model生成創建SQL Server數據庫表腳本的示例,幫助大家更好的理解和學習使用.net框架,感興趣的朋友可以了解下

  在我們的項目中經常采用Model First這種方式先來設計數據庫Model,然后通過Migration來生成數據庫表結構,有些時候我們需要動態通過實體Model來創建數據庫的表結構,特別是在創建像臨時表這一類型的時候,我們直接通過代碼來進行創建就可以了不用通過創建實體然后遷移這種方式來進行,其實原理也很簡單就是通過遍歷當前Model然后獲取每一個屬性并以此來生成部分創建腳本,然后將這些創建的腳本拼接成一個完整的腳本到數據庫中去執行就可以了,只不過這里有一些需要注意的地方,下面我們來通過代碼來一步步分析怎么進行這些代碼規范編寫以及需要注意些什么問題。

  一  代碼分析

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/// <summary>
    /// Model 生成數據庫表腳本
    /// </summary>
    public class TableGenerator : ITableGenerator {
        private static Dictionary<Type, string> DataMapper {
            get {
                var dataMapper = new Dictionary<Type, string> {
                    {typeof(int), "NUMBER(10) NOT NULL"},
                    {typeof(int?), "NUMBER(10)"},
                    {typeof(string), "VARCHAR2({0} CHAR)"},
                    {typeof(bool), "NUMBER(1)"},
                    {typeof(DateTime), "DATE"},
                    {typeof(DateTime?), "DATE"},
                    {typeof(float), "FLOAT"},
                    {typeof(float?), "FLOAT"},
                    {typeof(decimal), "DECIMAL(16,4)"},
                    {typeof(decimal?), "DECIMAL(16,4)"},
                    {typeof(Guid), "CHAR(36)"},
                    {typeof(Guid?), "CHAR(36)"}
                };
 
                return dataMapper;
            }
        }
 
        private readonly List<KeyValuePair<string, PropertyInfo>> _fields = new List<KeyValuePair<string, PropertyInfo>>();
 
        /// <summary>
        ///
        /// </summary>
        private string _tableName;
 
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        private string GetTableName(MemberInfo entityType) {
            if (_tableName != null)
                return _tableName;
            var prefix = entityType.GetCustomAttribute<TempTableAttribute>() != null ? "#" : string.Empty;
            return _tableName = $"{prefix}{entityType.GetCustomAttribute<TableAttribute>()?.Name ?? entityType.Name}";
        }
 
        /// <summary>
        /// 生成創建表的腳本
        /// </summary>
        /// <returns></returns>
        public string GenerateTableScript(Type entityType) {
            if (entityType == null)
                throw new ArgumentNullException(nameof(entityType));
 
            GenerateFields(entityType);
 
            const int DefaultColumnLength = 500;
            var script = new StringBuilder();
 
            script.AppendLine($"CREATE TABLE {GetTableName(entityType)} (");
            foreach (var (propName, propertyInfo) in _fields) {
                if (!DataMapper.ContainsKey(propertyInfo.PropertyType))
                    throw new NotSupportedException($"尚不支持 {propertyInfo.PropertyType}, 請聯系開發人員.");
                if (propertyInfo.PropertyType == typeof(string)) {
                    var maxLengthAttribute = propertyInfo.GetCustomAttribute<MaxLengthAttribute>();
                    script.Append($"\t {propName} {string.Format(DataMapper[propertyInfo.PropertyType], maxLengthAttribute?.Length ?? DefaultColumnLength)}");
                    if (propertyInfo.GetCustomAttribute<RequiredAttribute>() != null)
                        script.Append(" NOT NULL");
                    script.AppendLine(",");
                } else {
                    script.AppendLine($"\t {propName} {DataMapper[propertyInfo.PropertyType]},");
                }
            }
 
            script.Remove(script.Length - 1, 1);
 
            script.AppendLine(")");
 
            return script.ToString();
        }
 
        private void GenerateFields(Type entityType) {
            foreach (var p in entityType.GetProperties()) {
                if (p.GetCustomAttribute<NotMappedAttribute>() != null)
                    continue;
                var columnName = p.GetCustomAttribute<ColumnAttribute>()?.Name ?? p.Name;
                var field = new KeyValuePair<string, PropertyInfo>(columnName, p);
                _fields.Add(field);
            }
        }
    }

  這里的TableGenerator繼承自接口ITableGenerator,在這個接口內部只定義了一個 string GenerateTableScript(Type entityType) 方法。

?
1
2
3
4
5
6
7
8
9
10
/// <summary>
    /// Model 生成數據庫表腳本
    /// </summary>
    public interface ITableGenerator {
        /// <summary>
        /// 生成創建表的腳本
        /// </summary>
        /// <returns></returns>
        string GenerateTableScript(Type entityType);
    }

  這里我們來一步步分析這些部分的含義,這個里面DataMapper主要是用來定義一些C#基礎數據類型和數據庫生成腳本之間的映射關系。

     1  GetTableName

  接下來我們看看GetTableName這個函數,這里首先來當前Model是否定義了TempTableAttribute,這個看名字就清楚了就是用來定義當前Model是否是用來生成一張臨時表的。

?
1
2
3
4
5
6
7
/// <summary>
    /// 是否臨時表, 僅限 Dapper 生成 數據庫表結構時使用
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
    public class TempTableAttribute : Attribute {
 
    }

  具體我們來看看怎樣在實體Model中定義TempTableAttribute這個自定義屬性。

?
1
2
3
4
5
6
7
8
[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的名稱,這里也舉一個實例。

?
1
2
3
4
5
[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。

  當然一個完整的代碼怎么能少得了單元測試呢?下面我們來看看單元測試。

  二  單元測試

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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的腳本。

?
1
2
3
4
CREATE TABLE Test (
     IntProperty NUMBER(10) NOT NULL,
     NullableIntProperty NUMBER(10),
)

          2  生成的臨時表的腳本。

?
1
2
3
4
5
CREATE TABLE #StringTable (
     DefaultString VARCHAR2(500 CHAR),
     LengthString VARCHAR2(30 CHAR),
     NotNullString VARCHAR2(500 CHAR) NOT NULL,
)

  通過這種方式我們就能夠在代碼中去動態生成數據庫表結構了。

以上就是EFCore 通過實體Model生成創建SQL Server數據庫表腳本的詳細內容,更多關于EFCore 創建SQL Server數據庫表腳本的資料請關注服務器之家其它相關文章!

原文鏈接:https://www.cnblogs.com/seekdream/p/11078231.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 在线99| 亚洲午夜精品 | 91精品国产日韩91久久久久久 | 欧美在线观看一区 | 亚洲激情av| 日韩有码在线观看 | 亚洲视频一区二区三区 | 在线精品一区 | 亚洲成人网一区 | 国产欧美日韩精品一区 | 精品96久久久久久中文字幕无 | 一区二区av在线 | 九色91九色porny永久 | 亚洲一区二区福利 | 在线中文字幕视频 | 五月婷婷精品 | 国产精品久久久久久久久久免费 | 日本一区二区视频 | 欧美激情一区二区 | 精品国产乱码久久久久久影片 | 国产 日韩 欧美 在线 | 午夜视频在线观看网站 | 中文字幕视频在线 | 天天干夜夜操 | 国产精品久久久久av | 中日韩一线二线三线视频 | 97天堂| 中文字幕一区日韩精品欧美 | 亚洲精品久久久一区二区三区 | 国产在线精品一区 | 国产综合视频在线观看 | 国产精品久久久久久亚洲调教 | 色网站在线免费观看 | 中文字幕精品一区久久久久 | 中文字幕在线三区 | 成人情趣视频 | 成人免费大片黄在线播放 | 欧美精品导航 | 国产裸体永久免费视频网站 | 国产精品久久久久久久久久免费看 | 日韩在线一区二区 |