NewLife.XCode是一个有10多年历史的开源数据中间件,由新生命团队(2002~2024)开发完成并维护至今,以下简称XCode。
整个系列教程会大量结合示例代码和运行日志来进行深入分析,蕴含多年开发经验于其中。
开源地址:https://github.com/NewLifeX/NewLife.XCode (求star, 620+)
XCode代码生成的最佳实践是 xcodetool.exe + Model.xml ,码神工具仍可生成实体类代码,但缺乏维护可能有兼容问题。熟练开发者可使用 dotnet tool install xcodetool -g 安装工具,并使用全局命令 xcode + Model.xml 来生成代码。
代码生成
数据模型文件是XCode数据库开发的中心,曾经流行和支持的DB First和Entity First,经过10多年优胜劣汰,只剩下Model First。
XCode的数据模型文件就是一个Model.xml,(名字可变),同目录配套xcodetool.exe,用于生成基于xml模型文件的多个实体类文件。
核心用法,编辑模型文件model.xml后,双击运行同目录的xcodetool.exe即可根据model.xml生成多个实体类文件!
如果手头没有model.xml,在空白目录运行xcodetool.exe会自动生成一个例子文件。
代码生成工具:http://x.newlifex.com/xcodetool.exe
该工具也可以在XCode源码中编译XCodeTool发布得到。
全局工具生成代码
xcodetool工具随着XCode发布最新版,可通过dotnet tool来安装。新建build.bat批处理文件,写入以下代码:
@echo off
xcode
IF ERRORLEVEL 1 (
echo xcode 命令执行失败,正在安装 .NET 工具...
dotnet tool install xcodetool -g --prerelease
xcode
)
双击运行build.bat,相同目录和子目录的*.xml模型文件将会自动生成实体类代码文件。如果找不到xml模型文件,则自动输出Model.xml文件作为模板。
BuildTT生成(已废弃)
(注:2022年开始,以下build.tt用法已过时,不推荐使用)
XCode的数据模型文件就是一个Model.xml,(名字可变),同目录配套Build.tt,用于在vs里调用XCode生成基于xml模型文件的多个实体类文件。
核心用法,在build.tt文件上点击右键选择“运行自定义工具”,即可根据model.xml生成多个实体类文件!
Nuget安装模版
从nuget安装NewLife.XCode时,可以看到项目下多了一个Model.xml和build.tt/build_netcore.tt
nfx项目安装NewLife.XCode才有,netcore项目可从nfx项目中拷贝这两个文件,或者修改项目为netcore+net45混合项目后再安装引用。
(!!!安装XCode后,编译一次项目,确保输出目录中存在newlife.core.dll和xcode.dll,因为build.tt内需要引用这两个文件,也可以拷贝这两个文件到别处并修改build.tt内部引用)
直接下载模版
可以直接下载 https://x.newlifex.com/XCode_BuildModel.zip ,确保build.tt/build_netcore.tt文件属性中的自定义工具为 TextTemplatingFileGenerator 。
解压拷贝model.xml和build.tt(netcore项目选build_netcore.tt)到需要放置实体类的目标目录。
手工编写模版(解决.NET5.0报错)
*.tt文件本质上就是VisualStudio的T4模版,可以在vs中新建一个,并确保其文件属性中的自定义工具为 TextTemplatingFileGenerator 。
build.tt和model.xml的文件名都可以随意修改,build.tt默认会自动查找当前目录的第一个xml文件来使用。或者修改build.tt文件内容,强制指定文件名
<#@ template language="C#" hostSpecific="true" debug="true" #>
<#@ assembly name="netstandard" #>
<#@ assembly name="$(SolutionDir)\DLL\NewLife.Core.dll" #>
<#@ assembly name="$(SolutionDir)\DLL\XCode.dll" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="XCode.Code" #>
<#@ output extension=".log" #>
<#
// 设置当前工作目录
PathHelper.BasePath = Host.ResolvePath(".");
// 导入模型文件并生成实体类,模型文件、输出目录、命名空间、连接名、中文文件名、表名字段名大小写
//EntityBuilder.Build(String xmlFile = null, String output = null, String nameSpace = null, String connName = null, Boolean? chineseFileName = true,Boolean? nameIgnoreCase = null);
EntityBuilder.Build();
//var tables = DAL.ImportFrom("Company.Project.xml");
//EntityBuilder.Build(tables);
#>
在.NETCore3.1/.NET5.0项目使用XCode的build_netcore.tt模板生成时,可能会报以下错误(未能找到文件):
或者报以下错误(正在编译转换:类型"Object"在未引用的程序集中定义。必须添加对程序集的引用):
这是VisualStudio2019的T4模板存在对.NET5.0程序集的兼容问题,只需要强制指定DLL引用位置即可。
上面文件中指定使用解决方案下DLL子目录的NewLife.Core.dll和XCode.dll,需要首先编译任意引用了XCode的项目,并在输出目录中寻找这两个文件,拷贝到DLL子目录中去。
此外,还可以修改 EntityBuilder.Build 参数来满足个性化需求。
NETCore项目模版生成报错
在.NETCore3.1/.NET5.0项目使用XCode的build.tt模板生成时,会报错:
此时我们可以修改模板
码神工具导出模型
码神工具下载地址 http://x.newlifex.com/XCoder_Install.exe 。
安装后启动,菜单中选择“数据建模工具”,会自动列出本机安装的数据库。
(也可以修改配置文件XCoder.exe.config,加入开发数据库的连接信息)
选择并连接数据库,可以看到该库的所有表信息,此时只需要“导出模型”,即可得到该库的model.xml模型文件。
(码神工具在早期2002~2012是XCode的唯一代码生成方式,现在仍可以使用,但由于缺乏维护可能存在一些兼容问题,推荐使用最新的build.tt+model.xml)
数据模型文件
Model.xml正是供我们进行数据建模的参考,同时也是XCode内部Membership的模型文件。
<?xml version="1.0" encoding="utf-8"?>
<EntityModel xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:schemaLocation="https://newlifex.com https://newlifex.com/Model202309.xsd" Document="https://newlifex.com/xcode/model" xmlns="https://newlifex.com/Model202309.xsd">
<Option>
<!--类名模板。其中{name}替换为Table.Name,如{name}Model/I{name}Dto等-->
<ClassNameTemplate />
<!--显示名模板。其中{displayName}替换为Table.DisplayName-->
<DisplayNameTemplate />
<!--基类。可能包含基类和接口,其中{name}替换为Table.Name-->
<BaseClass>Entity</BaseClass>
<!--命名空间-->
<Namespace>XCode.Membership</Namespace>
<!--输出目录-->
<Output>.\</Output>
<!--是否使用中文文件名。默认false-->
<ChineseFileName>True</ChineseFileName>
<!--用于生成Copy函数的参数类型。例如{name}或I{name}-->
<ModelNameForCopy>{name}Model</ModelNameForCopy>
<!--带有索引器。实现IModel接口-->
<HasIModel>True</HasIModel>
<!--可为null上下文。生成String?等-->
<Nullable>True</Nullable>
<!--数据库连接名-->
<ConnName>Membership</ConnName>
<!--模型类模版。设置后生成模型类,用于接口数据传输,例如{name}Model-->
<ModelClass>{name}Model</ModelClass>
<!--模型类输出目录。默认当前目录的Models子目录-->
<ModelsOutput>.\Models\</ModelsOutput>
<!--模型接口模版。设置后生成模型接口,用于约束模型类和实体类,例如I{name}-->
<ModelInterface>I{name}</ModelInterface>
<!--模型接口输出目录。默认当前目录的Interfaces子目录-->
<InterfacesOutput>.\Interfaces\</InterfacesOutput>
<!--用户实体转为模型类的模型类。例如{name}或{name}DTO-->
<ModelNameForToModel />
<!--命名格式。Default/Upper/Lower/Underline-->
<NameFormat>Default</NameFormat>
<!--魔方区域显示名-->
<DisplayName />
<!--魔方控制器输出目录-->
<CubeOutput />
</Option>
<Tables>
<Table Name="User" Description="用户。用户帐号信息,以身份验证为中心,拥有多种角色,可加入多个租户">
<Columns>
<Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="编号" />
<Column Name="Name" DataType="String" Master="True" Nullable="False" Description="名称。登录用户名" />
<Column Name="Password" DataType="String" Length="200" Description="密码" />
<Column Name="DisplayName" DataType="String" Description="昵称" />
<Column Name="Sex" DataType="Int32" Description="性别。未知、男、女" Type="XCode.Membership.SexKinds" />
<Column Name="Mail" DataType="String" ItemType="mail" Description="邮件。支持登录" />
<Column Name="Mobile" DataType="String" ItemType="mobile" Description="手机。支持登录" />
<Column Name="Code" DataType="String" Description="代码。身份证、员工编码等,支持登录" />
<Column Name="AreaId" DataType="Int32" Map="XCode.Membership.Area@Id@Path@AreaPath" Description="地区。省市区" />
<Column Name="Avatar" DataType="String" ItemType="image" Length="200" Description="头像" />
<Column Name="RoleID" DataType="Int32" Map="Role@Id@Name" DefaultValue="3" Description="角色。主要角色" Category="登录信息" />
<Column Name="RoleIds" DataType="String" Length="200" Description="角色组。次要角色集合" Category="登录信息" />
<Column Name="DepartmentID" DataType="Int32" Map="Department@Id@Name" Description="部门。组织机构" Category="登录信息" />
<Column Name="Online" DataType="Boolean" Description="在线" Category="登录信息" />
<Column Name="Enable" DataType="Boolean" Description="启用" Category="登录信息" />
<Column Name="Age" DataType="Int32" Description="年龄。周岁" />
<Column Name="Birthday" DataType="DateTime" Description="生日。公历年月日" />
<Column Name="Logins" DataType="Int32" Description="登录次数" Category="登录信息" />
<Column Name="LastLogin" DataType="DateTime" Description="最后登录" Category="登录信息" />
<Column Name="LastLoginIP" DataType="String" Description="最后登录IP" Category="登录信息" />
<Column Name="RegisterTime" DataType="DateTime" Description="注册时间" Category="登录信息" />
<Column Name="RegisterIP" DataType="String" Description="注册IP" Category="登录信息" />
<Column Name="OnlineTime" DataType="Int32" ItemType="TimeSpan" Description="在线时间。累计在线总时间,单位秒" Category="登录信息" />
<Column Name="Ex1" DataType="Int32" Description="扩展1" Category="扩展" />
<Column Name="Ex2" DataType="Int32" Description="扩展2" Category="扩展" />
<Column Name="Ex3" DataType="Double" Description="扩展3" Category="扩展" />
<Column Name="Ex4" DataType="String" Description="扩展4" Category="扩展" />
<Column Name="Ex5" DataType="String" Description="扩展5" Category="扩展" />
<Column Name="Ex6" DataType="String" Description="扩展6" Attribute="XmlIgnore, ScriptIgnore, IgnoreDataMember" Category="扩展" />
<Column Name="UpdateUser" DataType="String" Nullable="False" DefaultValue="''" Description="更新者" Model="False" Category="扩展" />
<Column Name="UpdateUserID" DataType="Int32" Description="更新用户" Model="False" Category="扩展" />
<Column Name="UpdateIP" DataType="String" Description="更新地址" Model="False" Category="扩展" />
<Column Name="UpdateTime" DataType="DateTime" Nullable="False" Description="更新时间" Model="False" Category="扩展" />
<Column Name="Remark" DataType="String" Length="500" Description="备注" Category="扩展" />
</Columns>
<Indexes>
<Index Columns="Name" Unique="True" />
<Index Columns="Mail" />
<Index Columns="Mobile" />
<Index Columns="Code" />
<Index Columns="RoleID" />
<Index Columns="UpdateTime" />
</Indexes>
</Table>
<Table Name="Department" Description="部门。组织机构,多级树状结构,支持多租户">
<Columns>
<Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="编号" />
<Column Name="TenantId" DataType="Int32" Map="Tenant@Id@$" Description="租户" />
<Column Name="Code" DataType="String" Description="代码" />
<Column Name="Name" DataType="String" Master="True" Nullable="False" Description="名称" />
<Column Name="FullName" DataType="String" Length="200" Description="全名" />
<Column Name="ParentID" DataType="Int32" Description="父级" />
<Column Name="Level" DataType="Int32" Description="层级。树状结构的层级" />
<Column Name="Sort" DataType="Int32" Description="排序。同级内排序" />
<Column Name="Enable" DataType="Boolean" Description="启用" />
<Column Name="Visible" DataType="Boolean" Description="可见" />
<Column Name="ManagerId" DataType="Int32" Map="User@Id@$" Description="管理者" />
<Column Name="Ex1" DataType="Int32" Description="扩展1" Category="扩展" />
<Column Name="Ex2" DataType="Int32" Description="扩展2" Category="扩展" />
<Column Name="Ex3" DataType="Double" Description="扩展3" Category="扩展" />
<Column Name="Ex4" DataType="String" Description="扩展4" Category="扩展" />
<Column Name="Ex5" DataType="String" Description="扩展5" Category="扩展" />
<Column Name="Ex6" DataType="String" Description="扩展6" Category="扩展" />
<Column Name="CreateUser" DataType="String" Description="创建者" Category="扩展" />
<Column Name="CreateUserID" DataType="Int32" Description="创建用户" Category="扩展" />
<Column Name="CreateIP" DataType="String" Description="创建地址" Category="扩展" />
<Column Name="CreateTime" DataType="DateTime" Nullable="False" Description="创建时间" Category="扩展" />
<Column Name="UpdateUser" DataType="String" Description="更新者" Category="扩展" />
<Column Name="UpdateUserID" DataType="Int32" Description="更新用户" Category="扩展" />
<Column Name="UpdateIP" DataType="String" Description="更新地址" Category="扩展" />
<Column Name="UpdateTime" DataType="DateTime" Nullable="False" Description="更新时间" Category="扩展" />
<Column Name="Remark" DataType="String" Length="500" Description="备注" Category="扩展" />
</Columns>
<Indexes>
<Index Columns="Name" />
<Index Columns="ParentID,Name" />
<Index Columns="Code" />
<Index Columns="UpdateTime" />
<Index Columns="TenantId" />
</Indexes>
</Table>
<Table Name="Role" Description="角色。业务场景中的岗位,功能权限的集合。不管是用户还是租户,都以角色来管理权限">
<Columns>
<Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="编号" />
<Column Name="Name" DataType="String" Master="True" Nullable="False" Description="名称" />
<Column Name="Enable" DataType="Boolean" Description="启用" />
<Column Name="IsSystem" DataType="Boolean" Description="系统。用于业务系统开发使用,不受数据权限约束,禁止修改名称或删除" />
<Column Name="Permission" DataType="String" Length="-1" Description="权限。对不同资源的权限,逗号分隔,每个资源的权限子项竖线分隔" />
<Column Name="Sort" DataType="Int32" Description="排序" />
<Column Name="Ex1" DataType="Int32" Description="扩展1" Category="扩展" />
<Column Name="Ex2" DataType="Int32" Description="扩展2" Category="扩展" />
<Column Name="Ex3" DataType="Double" Description="扩展3" Category="扩展" />
<Column Name="Ex4" DataType="String" Description="扩展4" Category="扩展" />
<Column Name="Ex5" DataType="String" Description="扩展5" Category="扩展" />
<Column Name="Ex6" DataType="String" Description="扩展6" Category="扩展" />
<Column Name="CreateUser" DataType="String" Description="创建者" Category="扩展" />
<Column Name="CreateUserID" DataType="Int32" Description="创建用户" Category="扩展" />
<Column Name="CreateIP" DataType="String" Description="创建地址" Category="扩展" />
<Column Name="CreateTime" DataType="DateTime" Nullable="False" Description="创建时间" Category="扩展" />
<Column Name="UpdateUser" DataType="String" Description="更新者" Category="扩展" />
<Column Name="UpdateUserID" DataType="Int32" Description="更新用户" Category="扩展" />
<Column Name="UpdateIP" DataType="String" Description="更新地址" Category="扩展" />
<Column Name="UpdateTime" DataType="DateTime" Nullable="False" Description="更新时间" Category="扩展" />
<Column Name="Remark" DataType="String" Length="500" Description="备注" Category="扩展" />
</Columns>
<Indexes>
<Index Columns="Name" Unique="True" />
</Indexes>
</Table>
<Table Name="Menu" Description="菜单。功能权限,大多数时候也是可见页面" BaseType="EntityTree">
<Columns>
<Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="编号" />
<Column Name="Name" DataType="String" Master="True" Nullable="False" Description="名称" />
<Column Name="DisplayName" DataType="String" Description="显示名" />
<Column Name="FullName" DataType="String" Length="200" Description="全名" />
<Column Name="ParentID" DataType="Int32" Description="父编号" />
<Column Name="Url" DataType="String" Length="200" Description="链接" />
<Column Name="Sort" DataType="Int32" Description="排序" />
<Column Name="Icon" DataType="String" Description="图标" />
<Column Name="Visible" DataType="Boolean" Description="可见" />
<Column Name="Necessary" DataType="Boolean" Description="必要。必要的菜单,必须至少有角色拥有这些权限,如果没有则自动授权给系统角色" />
<Column Name="NewWindow" DataType="Boolean" Description="新窗口。新窗口打开链接" />
<Column Name="Permission" DataType="String" Length="2000" Description="权限子项。逗号分隔,每个权限子项名值竖线分隔" />
<Column Name="Ex1" DataType="Int32" Description="扩展1" Category="扩展" />
<Column Name="Ex2" DataType="Int32" Description="扩展2" Category="扩展" />
<Column Name="Ex3" DataType="Double" Description="扩展3" Category="扩展" />
<Column Name="Ex4" DataType="String" Description="扩展4" Category="扩展" />
<Column Name="Ex5" DataType="String" Description="扩展5" Category="扩展" />
<Column Name="Ex6" DataType="String" Description="扩展6" Category="扩展" />
<Column Name="CreateUser" DataType="String" Description="创建者" Category="扩展" />
<Column Name="CreateUserID" DataType="Int32" Description="创建用户" Category="扩展" />
<Column Name="CreateIP" DataType="String" Description="创建地址" Category="扩展" />
<Column Name="CreateTime" DataType="DateTime" Nullable="False" Description="创建时间" Category="扩展" />
<Column Name="UpdateUser" DataType="String" Description="更新者" Category="扩展" />
<Column Name="UpdateUserID" DataType="Int32" Description="更新用户" Category="扩展" />
<Column Name="UpdateIP" DataType="String" Description="更新地址" Category="扩展" />
<Column Name="UpdateTime" DataType="DateTime" Nullable="False" Description="更新时间" Category="扩展" />
<Column Name="Remark" DataType="String" Length="500" Description="备注" Category="扩展" />
</Columns>
<Indexes>
<Index Columns="Name" />
<Index Columns="ParentID,Name" Unique="True" />
</Indexes>
</Table>
<Table Name="Parameter" Description="字典参数。管理用户或系统全局的名值对数据,常用于参数配置场合">
<Columns>
<Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="编号" />
<Column Name="UserID" DataType="Int32" Map="User@Id@$" Description="用户。按用户区分参数,用户0表示系统级" />
<Column Name="Category" DataType="String" Description="类别" />
<Column Name="Name" DataType="String" Master="True" Nullable="False" Description="名称" />
<Column Name="Value" DataType="String" Length="200" Description="数值" />
<Column Name="LongValue" DataType="String" Length="2000" Description="长数值" />
<Column Name="Kind" DataType="Int32" Description="种类。0普通,21列表,22名值" Type="XCode.Membership.ParameterKinds" />
<Column Name="Enable" DataType="Boolean" Description="启用" />
<Column Name="Ex1" DataType="Int32" Description="扩展1" Category="扩展" />
<Column Name="Ex2" DataType="Decimal" Precision="19" Scale="4" Description="扩展2" Category="扩展" />
<Column Name="Ex3" DataType="Double" Description="扩展3" Category="扩展" />
<Column Name="Ex4" DataType="String" Description="扩展4" Category="扩展" />
<Column Name="Ex5" DataType="String" Description="扩展5" Category="扩展" />
<Column Name="Ex6" DataType="String" Description="扩展6" Category="扩展" />
<Column Name="CreateUser" DataType="String" Description="创建者" Category="扩展" />
<Column Name="CreateUserID" DataType="Int32" Description="创建用户" Category="扩展" />
<Column Name="CreateIP" DataType="String" Description="创建地址" Category="扩展" />
<Column Name="CreateTime" DataType="DateTime" Nullable="False" Description="创建时间" Category="扩展" />
<Column Name="UpdateUser" DataType="String" Description="更新者" Category="扩展" />
<Column Name="UpdateUserID" DataType="Int32" Description="更新用户" Category="扩展" />
<Column Name="UpdateIP" DataType="String" Description="更新地址" Category="扩展" />
<Column Name="UpdateTime" DataType="DateTime" Nullable="False" Description="更新时间" Category="扩展" />
<Column Name="Remark" DataType="String" Length="500" Description="备注" Category="扩展" />
</Columns>
<Indexes>
<Index Columns="UserID,Category,Name" Unique="True" />
<Index Columns="Category,Name" />
<Index Columns="UpdateTime" />
</Indexes>
</Table>
<Table Name="Area" Description="地区。行政区划数据,最高支持四级地址,9位数字">
<Columns>
<Column Name="ID" DataType="Int32" PrimaryKey="True" Description="编码。行政区划编码" />
<Column Name="Name" DataType="String" Master="True" Nullable="False" Description="名称" />
<Column Name="FullName" DataType="String" Master="True" Description="全名" />
<Column Name="ParentID" DataType="Int32" Description="父级" />
<Column Name="Level" DataType="Int32" Description="层级" />
<Column Name="Kind" DataType="String" Description="类型。省市县,自治州等" />
<Column Name="English" DataType="String" Description="英文名" />
<Column Name="PinYin" DataType="String" Description="拼音" />
<Column Name="JianPin" DataType="String" Description="简拼" />
<Column Name="TelCode" DataType="String" Description="区号。电话区号" />
<Column Name="ZipCode" DataType="String" Description="邮编。邮政编码" />
<Column Name="Longitude" DataType="Double" Description="经度" />
<Column Name="Latitude" DataType="Double" Description="纬度" />
<Column Name="GeoHash" DataType="String" Description="地址编码。字符串前缀相同越多,地理距离越近,8位精度19米,6位610米" />
<Column Name="Enable" DataType="Boolean" Description="启用" />
<Column Name="CreateTime" DataType="DateTime" Description="创建时间" Category="扩展" />
<Column Name="UpdateTime" DataType="DateTime" Description="更新时间" Category="扩展" />
<Column Name="Remark" DataType="String" Length="500" Description="备注" Category="扩展" />
</Columns>
<Indexes>
<Index Columns="ParentID" />
<Index Columns="Name" />
<Index Columns="PinYin" />
<Index Columns="JianPin" />
<Index Columns="GeoHash" />
<Index Columns="UpdateTime,ID" />
</Indexes>
</Table>
<Table Name="Log" Description="日志。应用系统审计日志,记录用户的各种操作,禁止修改和删除" ConnName="Log" InsertOnly="True">
<Columns>
<Column Name="ID" DataType="Int64" PrimaryKey="True" Description="编号" />
<Column Name="Category" DataType="String" Description="类别" />
<Column Name="Action" DataType="String" Nullable="False" Description="操作" />
<Column Name="LinkID" DataType="Int64" Description="链接" />
<Column Name="Success" DataType="Boolean" Description="成功" />
<Column Name="UserName" DataType="String" Description="用户名" />
<Column Name="Ex1" DataType="Int32" Description="扩展1" Category="扩展" />
<Column Name="Ex2" DataType="Int32" Description="扩展2" Category="扩展" />
<Column Name="Ex3" DataType="Double" Description="扩展3" Category="扩展" />
<Column Name="Ex4" DataType="String" Description="扩展4" Category="扩展" />
<Column Name="Ex5" DataType="String" Description="扩展5" Category="扩展" />
<Column Name="Ex6" DataType="String" Description="扩展6" Category="扩展" />
<Column Name="TraceId" DataType="String" Description="性能追踪。用于APM性能追踪定位,还原该事件的调用链" />
<Column Name="CreateUser" DataType="String" Description="创建者" Category="扩展" />
<Column Name="CreateUserID" DataType="Int32" Map="User@Id@$" Description="创建用户" Category="扩展" />
<Column Name="CreateIP" DataType="String" Description="创建地址" Category="扩展" />
<Column Name="CreateTime" DataType="DateTime" Nullable="False" Description="时间" />
<Column Name="Remark" DataType="String" Length="2000" Description="详细信息" />
</Columns>
<Indexes>
<Index Columns="Action,Category,ID" />
<Index Columns="Category,LinkID,ID" />
<Index Columns="CreateUserID,ID" />
</Indexes>
</Table>
<Table Name="Tenant" Description="租户。多租户SAAS平台,用于隔离业务数据">
<Columns>
<Column Name="Id" DataType="Int32" Identity="True" PrimaryKey="True" Description="编号" />
<Column Name="Code" DataType="String" Description="编码。唯一编码" />
<Column Name="Name" DataType="String" Master="True" Nullable="False" Description="名称。显示名称" />
<Column Name="Enable" DataType="Boolean" Description="启用" />
<Column Name="ManagerId" DataType="Int32" Map="User@Id@$" Description="管理者" />
<Column Name="RoleIds" DataType="String" Length="200" Description="角色组。租户可选的角色集合,不同级别的租户所拥有的角色不一样,高级功能也会不同" />
<Column Name="Logo" DataType="String" ItemType="image" Description="图标。附件路径" />
<Column Name="DatabaseName" DataType="String" Description="数据库。分库用的数据库名" />
<Column Name="TableName" DataType="String" Description="数据表。分表用的数据表前缀" />
<Column Name="Expired" DataType="DateTime" Description="过期时间。达到该时间后,自动禁用租户,空表示永不过期" />
<Column Name="CreateUserId" DataType="Int32" Description="创建者" Model="False" Category="扩展" />
<Column Name="CreateTime" DataType="DateTime" Description="创建时间" Model="False" Category="扩展" />
<Column Name="CreateIP" DataType="String" Description="创建地址" Model="False" Category="扩展" />
<Column Name="UpdateUserId" DataType="Int32" Description="更新者" Model="False" Category="扩展" />
<Column Name="UpdateTime" DataType="DateTime" Description="更新时间" Model="False" Category="扩展" />
<Column Name="UpdateIP" DataType="String" Description="更新地址" Model="False" Category="扩展" />
<Column Name="Remark" DataType="String" Length="500" Description="描述" Category="扩展" />
</Columns>
<Indexes>
<Index Columns="Code" Unique="True" />
</Indexes>
</Table>
<Table Name="TenantUser" Description="租户关系。用户选择租户进入系统后,以租户关系角色组替代自有角色组来进行鉴权">
<Columns>
<Column Name="Id" DataType="Int32" Identity="True" PrimaryKey="True" Description="编号" />
<Column Name="TenantId" DataType="Int32" Map="Tenant@Id@$" Description="租户" />
<Column Name="UserId" DataType="Int32" Map="User@Id@$" Description="用户" />
<Column Name="Enable" DataType="Boolean" Description="启用" />
<Column Name="RoleId" DataType="Int32" Map="Role@Id@Name" Description="角色。用户在该租户所对应的主要角色,替换用户自身的角色组" />
<Column Name="RoleIds" DataType="String" Length="200" Description="角色组。次要角色集合" />
<Column Name="CreateUserId" DataType="Int32" Description="创建者" Model="False" Category="扩展" />
<Column Name="CreateTime" DataType="DateTime" Description="创建时间" Model="False" Category="扩展" />
<Column Name="CreateIP" DataType="String" Description="创建地址" Model="False" Category="扩展" />
<Column Name="UpdateUserId" DataType="Int32" Description="更新者" Model="False" Category="扩展" />
<Column Name="UpdateTime" DataType="DateTime" Description="更新时间" Model="False" Category="扩展" />
<Column Name="UpdateIP" DataType="String" Description="更新地址" Model="False" Category="扩展" />
<Column Name="Remark" DataType="String" Length="500" Description="描述" Category="扩展" />
</Columns>
<Indexes>
<Index Columns="TenantId,UserId" Unique="True" />
<Index Columns="UserId" />
</Indexes>
</Table>
</Tables>
</EntityModel>
头部属性解释:
- Output,输出目录
- NameSpace,命名空间
- ConnName,连接名,对应app.config/web.config中connectionStrings下的name
- BaseEntity,基类,默认Entity,同一个子模块也可以共用自己的泛型基类EntityBase
Tables中的这些属性对本模型文件所有Table有效,各个Table上也可以指定这些属性,以覆盖全局设置
Table.Name 就是生成的实体类类名,如果实际表名不同,可用TableName指定表名。
Column.Name就是生成的实体类属性名,如果实际字段名不同,可用ColumnName指定字段名。
字符串长度Length默认50,不建议小于50,-1表示最大ntext
其它字段不建议设置长度,特别不建议给Double和Decimal设置精度
字段Column只需要DataType指定.Net类型即可,反向工程会根据使用数据库的不同而映射到不同数据库类型。
如果不喜欢XCode推荐的数据库类型,可在Column中通过RawType指定原始数据库类型。
Column支持Type指定枚举类型,建议是带命名空间的全名。例如上面User表中Sex类型的字段就是枚举SexKinds
Indexes内放置该表所有索引。
每一行Index为一组索引,Columns内指定索引所需要的字段(注意先后顺序),Unique指定是否唯一索引。
!!XCode反向工程支持自动创建或删除索引。
可以通过码神工具/建模工具,从数据库中导出数据表对应的模型文件;
也可以编码通过DAL.Export导出模型文件;
魔方的系统管理数据库页面,也可以导出模型文件;
数据名字规范
模型文件的Table名将会生成实体类类名,Column字段名将会生成实体类属性名,因此命名规范很重要。
- 名称必须使用通俗易懂的英文单词全拼,常用的缩略词(如ID)除外
- 采用大驼峰命名,每个单词首字母大写,其它小写,类型属性名符合.Net规范
- 名称必须简洁明了,不要加多余的前缀(如表名前加tbl),字段名也不要加表名前缀
- 不得使用SQL关键字或C#关键字作为表名或字段名
- 使用数据库常用类型,如Int32和String,大文本长度-1
- 给表和字段加上说明,作为文件名,以及生成代码的注释
- 每张表必须有唯一主键字段(建议自增ID)
- 主从表中,从表加关联字段(主表名+主表主键名)。XCode会识别为主从关系,生成扩展属性
- 每张表设置好索引,注意是否唯一。XCode会识别为索引,生成扩展查询
数据类型规范
模型文件设计要求开发者有一点数据库基础,至少要能明确表、字段和索引的概念。
然而要求又远比数据库要低得多,因为咱们推崇极致简单的原则。
类型 |
| 数据库类型 | 推荐 | 备注 |
Int32 | 整数 | int | 强烈 | 优先 |
String | 字符串 | nvarchar(50) | 强烈 | 默认变长50 |
DateTime | 时间日期 | datetime | 强烈 | 不建议纯日期或时间 |
Boolean | 布尔型 | bit | 强烈 | MySql中建议tinyint替代枚举来实现布尔型 |
Int64 | 长整型 | long | 强烈 | 有可能超过21亿的整数,选长整型 |
Decimal | 十进制 | money | 慎用 | 高精度货币型时采用 |
Double | 双精度 | double | 慎用 | 特别慎用,避免浮点运算导致精度丢失 |
Int16 |
| short | 禁用 | 由Int32替代 |
Byte |
| tinyint | 禁用 | 由Int32替代 |
Single |
| single | 禁用 | 由Double替代 |
常用字段推荐
为了便于开发,XCode默认优待以下字段:
<Column Name="CreateUser" DataType="String" Description="创建者" />
<Column Name="CreateUserID" DataType="Int32" Description="创建者" />
<Column Name="CreateTime" DataType="DateTime" Description="创建时间" />
<Column Name="CreateIP" DataType="String" Description="创建地址" />
<Column Name="UpdateUser" DataType="String" Description="更新者" />
<Column Name="UpdateUserID" DataType="Int32" Description="更新者" />
<Column Name="UpdateTime" DataType="DateTime" Description="更新时间" />
<Column Name="UpdateIP" DataType="String" Description="更新地址" />
时间组CreateTime/UpdateTime字段对应TimeModule,在新增或更新时自动赋值;
IP组CreateIP/UpdateIP字段对应IPModule,在Web新增或更新时自动赋值;
用户组CreateUser(ID)/UpdateUser(ID)字段对应UserModule,在Web新增或更新时字段赋值;
一句话:用了这些字段,在Insert时自动给CreateAbc赋值,在Update时自动给UpdateAbc赋值!
最佳实践
多年开发经验积累,得到一些技巧:
- 珍藏自己最得意的模型文件model.xml,如有需要也可以珍藏build.tt
- 新建数据类库项目时,为每个模块建立子目录,其中放入build.tt+model.xml
- 修改model.xml的命名空间和连接名等设置
- 也可以根据项目性质,找到最接近的项目,拷贝其model.xml作为新项目模版
- 修改新项目模块的model.xml,根据设计逐步完善数据表和索引
- 根据团队开发习惯,不同表会有很多类似字段设计可重复使用,例如上面的常用字段推荐
- 在项目推进过程中,如有增加字段,XCode反向工程会自动给数据库加上,无需人工处理
- 开发阶段配置各个连接为本地SQLite数据库,若无配置,默认就是SQLite
- 发布生产环境时,再配置连接字符串为实际数据库,如MySql、Oracle、SqlServer,XCode确保跨数据库兼容。