- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章EFCore 通过实体Model生成创建SQL Server数据库表脚本由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
在我们的项目中经常采用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#基础数据类型和数据库生成脚本之间的映射关系.
接下来我们看看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啦.
这个主要是用来一个个读取Model中的属性,并将每一个实体属性整理成一个KeyValuePair<string, PropertyInfo>的对象从而方便最后一步来生成整个表完整的脚本,这里也有些内容需要注意,如果当前属性定义了NotMappedAttribute标签,那么我们可以直接跳过当前属性,另外还需要注意的地方就是当前属性的名称首先看当前属性是否定义了ColumnAttribute的如果定义了,那么数据库中字段名称就取自ColumnAttribute定义的名称,否则才是取自当前属性的名称,通过这样一步操作我们就能够将所有的属性读取到一个自定义的数据结构List<KeyValuePair<string, PropertyInfo>>里面去了.
有了前面的两步准备工作,后面就是进入到生成整个创建表脚本的部分了,其实这里也比较简单,就是通过循环来一个个生成每一个属性对应的脚本,然后通过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
2
3
4
|
CREATE
TABLE
Test (
IntProperty NUMBER(10)
NOT
NULL
,
NullableIntProperty NUMBER(10),
)
|
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 。
最后此篇关于EFCore 通过实体Model生成创建SQL Server数据库表脚本的文章就讲到这里了,如果你想了解更多关于EFCore 通过实体Model生成创建SQL Server数据库表脚本的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我对 mongoosejs 中模型的使用感到有些困惑。 可以通过这些方式使用 mongoose 创建模型 使用 Mongoose var mongoose = require('mongoose');
我正在看 from django.db import models class Publisher(models.Model): name = models.CharField(max_len
我有自己的 html 帮助器扩展,我用这种方式 model.Reason_ID, Register.PurchaseReason) %> 这样声明的。 public static MvcHtmlS
假设模型原本是存储在CPU上的,然后我想把它移到GPU0上,那么我可以这样做: device = torch.device('cuda:0') model = model.to(device) # o
我过去读过一些关于模型的 MVC 建议,指出不应为域和 View 重用相同的模型对象;但我找不到任何人愿意讨论为什么这很糟糕。 我认为创建两个单独的模型 - 一个用于域,一个用于 View - 然后在
我正在使用pytorch构建一个像VGG16这样的简单模型,并且我已经重载了函数forward在我的模型中。 我发现每个人都倾向于使用 model(input)得到输出而不是 model.forwar
tf.keras API 中的 models 是否多余?对于某些情况,即使不使用 models,代码也能正常运行。 keras.models.sequential 和 keras.sequential
当我尝试使用 docker 镜像运行 docker 容器时遇到问题:tensorflow/serving。 我运行命令: docker run --name=tf_serving -it tensor
我有一个模型,我用管道注册了它: register_step = PythonScriptStep(name = "Register Model",
如果 View 需要访问模型中的数据,您是否认为 Controller 应: a)将模型传递给 View b)将模型的数据传递给 View c)都不;这不应该是 Controller 所关心的。让 V
我正在寻找一个可以在模型中定义的字段,该字段本质上是一个列表,因为它将用于存储多个字符串值。显然CharField不能使用。 最佳答案 您正在描述一种多对一的关系。这应该通过一个额外的 Model 进
我最近了解了 Django 中的模型继承。我使用很棒的包 django-model-utils 取得了巨大的成功。我继承自 TimeStampedModel 和 SoftDeletableModel。
我正在使用基于 resnet50 的双输出模型进行项目。一个输出用于回归任务,第二个输出用于分类任务。 我的主要问题是关于模型评估。在训练期间,我在验证集的两个输出上都取得了不错的结果: - 综合损失
我是keras的新手。现在,我将使用我使用 model.fit_generator 训练的模型来预测测试图像组。我可以使用 model.predict 吗?不确定如何使用model.predict_g
在 MVC 应用程序中,我加入了多个表并将其从 Controller 返回到 View,如下所示: | EmployeeID | ControlID | DoorAddress | DoorID |
我在使用 sails-cassandra 连接系统的 Sails 中有一个 Data 模型。数据。 Data.count({...}).exec() 返回 1,但 Data.find({...}).e
我正在使用 PrimeFaces dataTable 开发一个 jsf 页面来显示用户列表。用户存储在 Model.User 类的对象中。
我正在关注https://www.tensorflow.org/tutorials/keras/basic_classification解决 Kaggle 挑战。 但是,我不明白应该将什么样的数据输入
我是这个领域的新手。那么,你们能帮忙如何为 CNN 创建 .config 文件吗? 传递有关如何执行此操作的文档或教程将对我有很大帮助。谢谢大家。 最佳答案 这个问题对我来说没有多大意义,因为 .co
我是“物理系统建模”主题的新手。我阅读了一些基础文献,并在 Modelica 和 Simulink/Simscape 中做了一些教程。我想问你,如果我对以下内容理解正确: 符号操作是将微分代数方程组(
我是一名优秀的程序员,十分优秀!