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字段名将会生成实体类属性名,因此命名规范很重要。

  1. 名称必须使用通俗易懂的英文单词全拼,常用的缩略词(如ID)除外
  2. 采用大驼峰命名,每个单词首字母大写,其它小写,类型属性名符合.Net规范
  3. 名称必须简洁明了,不要加多余的前缀(如表名前加tbl),字段名也不要加表名前缀
  4. 不得使用SQL关键字或C#关键字作为表名或字段名
  5. 使用数据库常用类型,如Int32和String,大文本长度-1
  6. 给表和字段加上说明,作为文件名,以及生成代码的注释
  7. 每张表必须有唯一主键字段(建议自增ID)
  8. 主从表中,从表加关联字段(主表名+主表主键名)。XCode会识别为主从关系,生成扩展属性
  9. 每张表设置好索引,注意是否唯一。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确保跨数据库兼容。