在开发商城系统的时候,大家会遇到这样的需求,商城系统里支持多种商品类型,比如衣服,手机,首饰等,每一种产品类型都有自己独有的参数信息,比如衣服有颜色,首饰有材质等,大家可以上淘宝看一下就明白了。现在的问题是,如果我程序发布后,要想增加一种新的商品类型怎么办,如果不在程序设计时考虑这个问题的话,可能每增加一个商品类型,就要增加对应商品类型的管理程序,并重新发布上线,对于维护来说成本会很高。有没有简单的方式可以快速增加新类型的支持?下面介绍的方案是这样的,首先把模型以配置的方式保存到配置文件中,在程序启动时解析模型信息编译成具体的类,然后通过ef实现动态编译类的数据库操作,如果新增类型,首先改下配置文件,然后在数据库中创建对应的数据库表,重启应用程序即可。
要实现这样的功能,需要解决以下几个问题:
1,如何实现动态模型的配置管理
2,如何根据模型配置在运行时动态生成类型
3,如何让ef识别动态类型
4,如何结合ef对动态类型信息进行操作,比如查询,增加等
一、如何实现动态模型的配置管理
这个问题解决的方案是,把模型的信息作为系统的一个配置文件,在系统运行时可以获取到模型配置信息。
首先定义一个类表示一个动态模型,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public
class
RuntimeModelMeta
{
public
int
ModelId {
get
;
set
; }
public
string
ModelName {
get
;
set
; }
//模型名称
public
string
ClassName {
get
;
set
; }
//类名称
public
ModelPropertyMeta[] ModelProperties {
get
;
set
; }
public
class
ModelPropertyMeta
{
public
string
Name {
get
;
set
; }
//对应的中文名称
public
string
PropertyName {
get
;
set
; }
//类属性名称
public
int
Length {
get
;
set
; }
//数据长度,主要用于string类型
public
bool
IsRequired {
get
;
set
; }
//是否必须输入,用于数据验证
public
string
ValueType {
get
;
set
; }
//数据类型,可以是字符串,日期,bool等
}
}
|
然后定义个配置类:
1
2
3
4
|
public
class
RuntimeModelMetaConfig
{
public
RuntimeModelMeta[] Metas {
get
;
set
; }
}
|
增加配置文件,文件名称为runtimemodelconfig.json,结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
{
"RuntimeModelMetaConfig"
: {
"Metas"
: [
{
"ModelId"
: 1,
"ModelName"
:
"衣服"
,
"ClassName"
:
"BareDiamond"
,
"ModelProperties"
: [
{
"Name"
:
"尺寸"
,
"PropertyName"
:
"Size"
,
},
{
"Name"
:
"颜色"
,
"PropertyName"
:
"Color"
,
}
]
}
]
}
}
|
下一步再asp.net core mvc的Startup类的构造方法中加入配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public
Startup(IHostingEnvironment env)
{
var
builder =
new
ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile(
"appsettings.json"
, optional:
true
, reloadOnChange:
true
)
.AddJsonFile(
"runtimemodelconfig.json"
, optional:
true
,reloadOnChange:
true
)
.AddEnvironmentVariables();
if
(env.IsDevelopment())
{
builder.AddApplicationInsightsSettings(developerMode:
true
);
}
Configuration = builder.Build();
}
|
然后再public void ConfigureServices(IServiceCollection services)方法中,获取到配置信息,代码如下:
1
2
3
4
5
6
|
public
void
ConfigureServices(IServiceCollection services)
{
。。。。。。
services.Configure<RuntimeModelMetaConfig>(Configuration.GetSection(
"RuntimeModelMetaConfig"
));
。。。。。。
}
|
到此就完成了配置信息的管理,在后续代码中可以通过依赖注入方式获取到IOptions<RuntimeModelMetaConfig>对象,然后通过IOptions<RuntimeModelMetaConfig>.Value.Metas获取到所有模型的信息。为了方便模型信息的管理,我这里定义了一个IRuntimeModelProvider接口,结构如下:
1
2
3
4
5
|
public
interface
IRuntimeModelProvider
{
Type GetType(
int
modelId);
Type[] GetTypes();
}
|
IRuntimeModelProvider.GetType方法可以通过modelId获取到对应的动态类型Type信息,GetTypes方法返回所有的动态类型信息。这个接口实现请看下面介绍。
二、如何根据模型配置在运行时动态生成类型
我们有了上面的配置后,需要针对模型动态编译成对应的类。C#提供了多种运行时动态生成类型的方式,下面我们介绍通过Emit来生成类,上面的配置信息比较适合模型配置信息的管理,对于生成类的话我们又定义了一个方便另外一个类,代码如下:
1
2
3
4
5
6
7
8
9
|