NewLife.XCode是一个有10多年历史的开源数据中间件,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode。
整个系列教程会大量结合示例代码和运行日志来进行深入分析,蕴含多年开发经验于其中。
开源地址:https://github.com/NewLifeX/X(求star, 620+)
数据模型文件
数据模型文件是XCode数据库开发的中心,曾经流行和支持的DB First和Entity First,经过10多年优胜劣汰,只剩下Model First。
XCode的数据模型文件就是一个Model.xml,(名字可变),同目录配套Build.tt,用于在vs里调用XCode生成基于xml模型文件的多个实体类文件。
从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内部引用)
其中的Model.xml正是供我们进行数据建模的参考,同时也是XCode内部Membership的模型文件。
<?xml version="1.0" encoding="utf-8"?>
<Tables Version="9.6.6663.16294" NameSpace="XCode.Membership" ConnName="Membership" Output="" BaseClass="Entity"
xmlns="http://www.newlifex.com/ModelSchema.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:schemaLocation="http://www.newlifex.com https://raw.githubusercontent.com/NewLifeX/X/master/XCode/ModelSchema.xsd" >
<Table Name="User" Description="用户" DbType="SqlServer" RenderGenEntity="true">
<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" Description="密码" />
<Column Name="DisplayName" DataType="String" Description="昵称" />
<Column Name="Sex" DataType="Int32" Description="性别。未知、男、女" Type="SexKinds" />
<Column Name="Mail" DataType="String" Description="邮件" />
<Column Name="Mobile" DataType="String" Description="手机" />
<Column Name="Code" DataType="String" Description="代码。身份证、员工编号等" />
<Column Name="Avatar" DataType="String" Length="200" Description="头像" />
<Column Name="RoleID" DataType="Int32" Description="角色。主要角色" />
<Column Name="RoleIDs" DataType="String" Length="200" Description="角色组。次要角色集合" />
<Column Name="Online" DataType="Boolean" Description="在线" />
<Column Name="Enable" DataType="Boolean" Description="启用" />
<Column Name="Logins" DataType="Int32" Description="登录次数" />
<Column Name="LastLogin" DataType="DateTime" Description="最后登录" />
<Column Name="LastLoginIP" DataType="String" Description="最后登录IP" />
<Column Name="RegisterTime" DataType="DateTime" Description="注册时间" />
<Column Name="RegisterIP" DataType="String" Description="注册IP" />
</Columns>
<Indexes>
<Index Columns="Name" Unique="True" />
<Index Columns="RoleID" />
</Indexes>
</Table>
<Table Name="Role" Description="角色" RenderGenEntity="true">
<Columns>
<Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="编号" />
<Column Name="Name" DataType="String" Master="True" Nullable="False" Description="名称" />
<Column Name="IsSystem" DataType="Boolean" Description="系统。用于业务系统开发使用,不受数据权限约束,禁止修改名称或删除" />
<Column Name="Remark" DataType="String" Description="说明" />
<Column Name="Permission" DataType="String" Length="500" Description="权限。对不同资源的权限,逗号分隔,每个资源的权限子项竖线分隔" />
<Column Name="CreateUserID" DataType="Int32" Description="创建用户" />
<Column Name="CreateIP" DataType="String" Description="创建地址" />
<Column Name="CreateTime" DataType="DateTime" Description="创建时间" />
<Column Name="UpdateUserID" DataType="Int32" Description="更新用户" />
<Column Name="UpdateIP" DataType="String" Description="更新地址" />
<Column Name="UpdateTime" DataType="DateTime" Description="更新时间" />
</Columns>
<Indexes>
<Index Columns="Name" Unique="True" />
</Indexes>
</Table>
<Table Name="Menu" Description="菜单" BaseType="EntityTree" RenderGenEntity="true">
<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="Permission" DataType="String" Length="200" Description="权限子项。逗号分隔,每个权限子项名值竖线分隔" />
<Column Name="Remark" DataType="String" Length="200" Description="备注" />
</Columns>
<Indexes>
<Index Columns="Name" />
<Index Columns="ParentID,Name" Unique="True" />
</Indexes>
</Table>
<Table Name="Log" Description="日志" ConnName="Log" RenderGenEntity="true">
<Columns>
<Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="编号" />
<Column Name="Category" DataType="String" Description="类别" />
<Column Name="Action" DataType="String" Description="操作" />
<Column Name="LinkID" DataType="Int32" Description="链接" />
<Column Name="UserName" DataType="String" Description="用户名" />
<Column Name="CreateUserID" DataType="Int32" Description="用户编号" />
<Column Name="CreateIP" DataType="String" Description="IP地址" />
<Column Name="CreateTime" DataType="DateTime" Description="时间" />
<Column Name="Remark" DataType="String" Length="500" Description="详细信息" />
</Columns>
<Indexes>
<Index Columns="Category" />
<Index Columns="CreateUserID" />
<Index Columns="CreateTime" />
</Indexes>
</Table>
<Table Name="UserOnline" Description="用户在线" ConnName="Log">
<Columns>
<Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="编号" />
<Column Name="UserID" DataType="Int32" Description="用户" />
<Column Name="Name" DataType="String" Master="True" Description="名称" />
<Column Name="SessionID" DataType="String" Description="会话。Web的SessionID或Server的会话编号" />
<Column Name="Times" DataType="Int32" Description="次数" />
<Column Name="Page" DataType="String" Description="页面" />
<Column Name="Status" DataType="String" Length="200" Description="状态" />
<Column Name="OnlineTime" DataType="Int32" Description="在线时间。本次在线总时间,秒" />
<Column Name="CreateIP" DataType="String" Description="创建地址" />
<Column Name="CreateTime" DataType="DateTime" Description="创建时间" />
<Column Name="UpdateTime" DataType="DateTime" Description="修改时间" />
</Columns>
<Indexes>
<Index Columns="UserID" />
<Index Columns="SessionID" />
<Index Columns="CreateTime" />
</Indexes>
</Table>
<Table Name="VisitStat" Description="访问统计" ConnName="Log">
<Columns>
<Column Name="ID" DataType="Int32" Identity="True" PrimaryKey="True" Description="编号" />
<Column Name="Level" DataType="Int32" Description="层级" Type="XCode.Statistics.StatLevels" />
<Column Name="Time" DataType="DateTime" Description="时间" />
<Column Name="Page" DataType="String" Nullable="False" Description="页面" />
<Column Name="Title" DataType="String" Master="True" Description="标题" />
<Column Name="Times" DataType="Int32" Description="次数" />
<Column Name="Users" DataType="Int32" Description="用户" />
<Column Name="IPs" DataType="Int32" Description="IP" />
<Column Name="Error" DataType="Int32" Description="错误" />
<Column Name="Cost" DataType="Int32" Description="耗时。毫秒" />
<Column Name="MaxCost" DataType="Int32" Description="最大耗时。毫秒" />
<Column Name="CreateTime" DataType="DateTime" Description="创建时间" />
<Column Name="UpdateTime" DataType="DateTime" Description="更新时间" />
<Column Name="Remark" DataType="String" Length="500" Description="详细信息" />
</Columns>
<Indexes>
<Index Columns="Page,Level,Time" Unique="True" />
<Index Columns="Level,Time" />
</Indexes>
</Table>
</Tables>
真实项目开发中,一般数据层类库项目为不同子模块划分目录,每个目录有自己的Model.xml+Build.tt,负责本模块的模型维护已经实体类生成。
头部属性解释:
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赋值!
系列教程
NewLife.XCode教程系列[2019版]
- 增删改查入门。快速展现用法,代码配置连接字符串
- 数据模型文件。建立表格字段和索引,名字以及数据类型规范,推荐字段(时间,用户,IP)
- 实体类详解。数据类业务类,泛型基类,接口
- 功能设置。连接字符串,调试开关,SQL日志,慢日志,参数化,执行超时。代码与配置文件设置,连接字符串局部设置
- 反向工程。自动建立数据库数据表
- 数据初始化。InitData写入初始化数据
- 高级增删改。重载拦截,自增字段,Valid验证,实体模型(时间,用户,IP)
- 脏数据。如何产生,怎么利用
- 增量累加。高并发统计
- 事务处理。单表和多表,不同连接,多种写法
- 扩展属性。多表关联,Map映射
- 高级查询。复杂条件,分页,自定义扩展FieldItem,查总记录数,查汇总统计
- 数据层缓存。Sql缓存,更新机制
- 实体缓存。全表整理缓存,更新机制
- 对象缓存。字典缓存,适用用户等数据较多场景。
- 百亿级性能。字段精炼,索引完备,合理查询,充分利用缓存
- 实体工厂。元数据,通用处理程序
- 角色权限。Membership
- 导入导出。Xml,Json,二进制,网络或文件
- 分表分库。常见拆分逻辑
- 高级统计。聚合统计,分组统计
- 批量写入。批量插入,批量Upsert,异步保存
- 实体队列。写入级缓存,提升性能。
- 备份同步。备份数据,恢复数据,同步数据
- 数据服务。提供RPC接口服务,远程执行查询,例如SQLite网络版
- 大数据分析。ETL抽取,调度计算处理,结果持久化