# XCode 协作指令

本指令面向新生命团队（NewLife）开源数据中间件 XCode，帮助 Copilot 在 .NET 项目中正确使用 XCode 进行数据建模和实体操作。

---

## 1. XCode 定位与边界

```
NewLife.Core（基础库）→ copilot-instructions.md
       ↓
   NewLife.XCode（数据中间件）← 本指令
       ↓
   NewLife.Cube（Web 快速开发框架）→ cube.instructions.md
```

**本指令覆盖**：数据模型设计（Model.xml）、实体类生成与使用、数据库 CRUD 操作、运行时配置、项目初始化与 XCode 接入。
**不包含**（由 `cube.instructions.md` 负责）：Web 控制器、视图与前端、权限管理、魔方区域深度定制。

### 1.1 支持的数据库

| 常用 | 国产/信创 | 时序/嵌入 |
|------|----------|----------|
| SqlServer、MySql、SQLite、PostgreSQL、Oracle | 达梦(DaMeng)、人大金仓(KingBase)、瀚高(HighGo)、VastBase | TDengine、InfluxDB、NovaDb |

> 另支持 DB2、Hana、IRIS、Access 等，完整列表见 `DatabaseType` 枚举。

---

## 2. 使用场景与快速入口

### 2.1 场景一：已有项目接入 XCode

1. 引入 NuGet 包：`dotnet add package NewLife.XCode`
2. 创建或编辑 `Model.xml` 进行数据建模
3. 执行 `xcode` 命令生成实体类
4. 在业务代码中使用实体类进行数据操作

### 2.2 场景二：从零创建新项目

1. 安装模板：`dotnet new install NewLife.Templates`
2. 创建数据类库：`dotnet new xcode -n {系统名}.Data`
3. 创建应用项目：
   - Web 应用：`dotnet new cube -n {系统名}Web`
   - 控制台应用：`dotnet new nconsole -n {系统名}App`
4. 编辑 `Model.xml` 进行数据建模
5. 执行 `xcode` 生成实体类

### 2.3 核心工作流

```
理解业务需求 → 数据建模(Model.xml) → 生成实体类(xcode) → 编写业务代码
```

**关键点**：无论哪种场景，核心都是 **充分理解业务需求，在 Model.xml 中设计合理的数据表结构**。

---

## 3. 环境准备

### 3.1 前置要求

```powershell
# 检查 .NET SDK（要求 8.0+）
dotnet --version

# 安装全局工具 xcodetool
dotnet tool install xcodetool -g
```

### 3.2 模板版本检查

NewLife.Templates 模板会持续更新，使用前需检查版本：

```powershell
# 查看模板详情
dotnet new details NewLife.Templates
```

**判定规则**：输出包含类似 `包版本: 1.1.2025.820-beta1836`
- 其中 `1.1.2025.820` 表示 v1.1，发布日期为 2025-08-20
- **要求**：发布日期需 > 2025-08-01（即严格晚于 2025-08-01）

```powershell
# 若未安装或版本过旧，执行安装/更新
dotnet new install NewLife.Templates
```

> **强约束**：仅当未安装或发布日期 ≤ 2025-08-01 时才执行安装；否则保持现状，避免无谓变更。

### 3.3 模板说明

| 模板 | 命令 | 用途 |
|------|------|------|
| `xcode` | `dotnet new xcode -n Name.Data` | 数据类库项目 |
| `cube` | `dotnet new cube -n NameWeb` | Web 管理后台 |
| `nconsole` | `dotnet new nconsole -n NameApp` | 控制台应用 |

---

## 4. Model.xml 完整参考

### 4.1 文件结构

```xml
<?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/Model202509.xsd" 
             xmlns="https://newlifex.com/Model202509.xsd">
  <Option>
    <!-- 全局配置 -->
  </Option>
  <Tables>
    <Table>
      <Columns>
        <Column />
      </Columns>
      <Indexes>
        <Index />
      </Indexes>
    </Table>
  </Tables>
</EntityModel>
```

### 4.2 Option 配置项

| 配置项 | 说明 | 示例 |
|--------|------|------|
| `Namespace` | 命名空间 | `Zero.Data` |
| `ConnName` | 数据库连接名 | `Zero` |
| `Output` | 实体类输出目录 | `.\` |
| `BaseClass` | 实体基类 | `Entity` |
| `ChineseFileName` | 使用中文文件名 | `True` |
| `Nullable` | 生成可空引用类型 | `True` |
| `HasIModel` | 实现 IModel 接口 | `True` |
| `ModelClass` | 模型类模板 | `{name}Model` |
| `ModelsOutput` | 模型类输出目录 | `.\Models\` |
| `ModelInterface` | 模型接口模板 | `I{name}` |
| `InterfacesOutput` | 接口输出目录 | `.\Interfaces\` |
| `ClassNameTemplate` | 类名模板 | `{name}Model`/`I{name}Dto` |
| `DisplayNameTemplate` | 显示名模板 | `{displayName}` |
| `ModelNameForCopy` | Copy 函数参数类型 | `{name}`/`I{name}` |
| `ModelNameForToModel` | ToModel 转换目标类型 | `{name}`/`{name}DTO` |
| `ExtendNameSpace` | 额外引用命名空间（逗号分隔） | `System.Xml.Serialization` |
| `NameFormat` | 命名格式 | `Default`/`Upper`/`Lower`/`Underline` |
| `DisplayName` | 魔方区域显示名 | `订单管理` |
| `CubeOutput` | 魔方控制器输出目录 | `../../Web/Areas/Order` |

### 4.3 Table 属性

| 属性 | 说明 | 示例 |
|------|------|------|
| `Name` | 实体类名 | `User` |
| `TableName` | 数据库表名（可选，默认同 Name） | `sys_user` |
| `Description` | 表说明 | `用户。用户账号信息` |
| `ConnName` | 独立连接名（覆盖全局） | `Log` |
| `BaseType` | 基类（支持实体继承） | `EntityBase` |
| `InsertOnly` | 仅插入模式（日志表优化） | `True` |
| `IsView` | 视图标识 | `True` |

### 4.4 Column 属性完整参考

#### 基础属性

| 属性 | 说明 | 示例 |
|------|------|------|
| `Name` | 属性名 | `UserName` |
| `ColumnName` | 数据库列名（可选） | `user_name` |
| `DataType` | 数据类型 | `Int32`/`Int64`/`String`/`DateTime`/`Boolean`/`Double`/`Decimal` |
| `Description` | 字段说明 | `用户名。登录账号` |
| `Length` | 字符串长度 | `50`/`200`/`-1`（大文本） |
| `Precision` | 数值精度 | `18` |
| `Scale` | 小数位数 | `2` |

#### 主键与标识

| 属性 | 说明 | 示例 |
|------|------|------|
| `PrimaryKey` | 主键 | `True` |
| `Identity` | 自增标识 | `True` |
| `Master` | 主字段（业务主要字段） | `True` |

**主键设计约定**：
- 普通表：`Int32` 自增 → `PrimaryKey="True" Identity="True"`
- 大数据表：`Int64` 雪花 ID → `PrimaryKey="True" DataScale="time"`（不设 Identity）

#### 约束与默认值

| 属性 | 说明 | 示例 |
|------|------|------|
| `Nullable` | 允许空 | `False` |
| `DefaultValue` | 默认值 | `0`/`''`/`getdate()` |

#### 映射关系（Map）

格式：`表名@主键@显示字段@属性名`

| 格式 | 说明 | 示例 |
|------|------|------|
| `Table@Id@Name` | 基本映射（三段） | `Role@Id@Name` |
| `Table@Id@Name@RoleName` | 指定属性名（四段） | `Role@Id@Name@RoleName` |
| `NS.Table@Id@Path@AreaPath` | 完整命名空间 | `XCode.Membership.Area@Id@Path@AreaPath` |

#### 元素类型（ItemType）

用于魔方前端渲染，常用值：`image`、`file`、`mail`、`mobile`、`url`、`TimeSpan`、`GMK`、`html`、`code`、`json`。详细用法见 `cube.instructions.md`。

#### 显示选项（ShowIn）

控制字段在魔方各区域（List/Detail/AddForm/EditForm/Search）的显示。推荐具名列表语法：

```
ShowIn="List,Search"          # 仅 List 和 Search 显示
ShowIn="-EditForm,-Detail"    # 编辑表单和详情隐藏
ShowIn="All,-Detail"          # 全部显示，详情隐藏
```

区域别名：`List(L)`、`Detail(D)`、`AddForm(Add/A)`、`EditForm(Edit/E)`、`Search(S)`、`Form(F)`（同时控制 Add 和 Edit）

**语法二：管道分隔**
```
ShowIn="Y|Y|N||A"   # List=显示|Detail=显示|Add=隐藏|Edit=自动|Search=自动
```

**语法三：5字符掩码**
```
ShowIn="11110"      # 1=显示, 0=隐藏, A/?/-=自动
```

#### 分表字段（DataScale）

| 值 | 说明 |
|----|------|
| `time` | 大数据单表的时间字段（用于雪花 ID） |
| `timeShard:yyMMdd` | 分表字段，按日期格式分表 |

#### 其他属性

| 属性 | 说明 | 示例 |
|------|------|------|
| `Type` | 枚举类型 | `XCode.Membership.SexKinds` |
| `Category` | 表单分组 | `登录信息`/`扩展` |
| `Attribute` | 额外特性 | `XmlIgnore, IgnoreDataMember` |
| `Model` | 是否包含在模型类中 | `False` |
| `RawType` | 原始数据库类型 | `varchar(50)` |

### 4.5 Index 属性

| 属性 | 说明 | 示例 |
|------|------|------|
| `Columns` | 索引列（逗号分隔） | `Name`/`Category,CreateTime` |
| `Unique` | 唯一索引 | `True` |

### 4.6 完整示例

```xml
<?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/Model202509.xsd" 
             xmlns="https://newlifex.com/Model202509.xsd">
  <Option>
    <Namespace>Order.Data</Namespace>
    <ConnName>Order</ConnName>
    <Output>.\</Output>
    <ChineseFileName>True</ChineseFileName>
    <Nullable>True</Nullable>
    <HasIModel>True</HasIModel>
    <DisplayName>订单管理</DisplayName>
    <CubeOutput>../../OrderWeb/Areas/Order</CubeOutput>
  </Option>
  <Tables>
    <Table Name="Order" Description="订单。电商订单主表">
      <Columns>
        <Column Name="Id" DataType="Int64" PrimaryKey="True" DataScale="time" Description="编号" />
        <Column Name="OrderNo" DataType="String" Master="True" Length="50" Nullable="False" Description="订单号" />
        <Column Name="UserId" DataType="Int32" Map="User@Id@Name" Description="用户" />
        <Column Name="Status" DataType="Int32" Type="Order.Data.OrderStatus" Description="状态" />
        <Column Name="TotalAmount" DataType="Decimal" Precision="18" Scale="2" Description="总金额" />
        <Column Name="Remark" DataType="String" Length="500" Description="备注" Category="扩展" />
        <Column Name="CreateUser" DataType="String" Description="创建者" Model="False" Category="扩展" />
        <Column Name="CreateTime" DataType="DateTime" Nullable="False" Description="创建时间" Category="扩展" />
        <Column Name="UpdateTime" DataType="DateTime" Description="更新时间" Model="False" Category="扩展" />
      </Columns>
      <Indexes>
        <Index Columns="OrderNo" Unique="True" />
        <Index Columns="UserId" />
        <Index Columns="Status,CreateTime" />
      </Indexes>
    </Table>
  </Tables>
</EntityModel>
```

---

## 5. 实体类操作指南

### 5.1 基础 CRUD

```csharp
// 新增
var entity = new User { Name = "test", Password = "123456" };
entity.Insert();

// 查询单个（按主键）
var user = User.FindByKey(1);
// 查询单个（按条件）
var user2 = User.Find(User._.Name == "test");

// 查询列表
var list = User.FindAll();
var list2 = User.FindAll(User._.Status == 1, User._.Id.Desc(), null, 0, 10);

// 更新
user.Name = "newName";
user.Update();

// 删除
user.Delete();

// 保存（自动判断 Insert/Update）
entity.Save();
```

### 5.2 高级查询

```csharp
// 分页查询
var page = new PageParameter { PageIndex = 1, PageSize = 20 };
var list = User.FindAll(User._.Status == 1, page);

// 条件组合
var where = new WhereExpression();
where &= User._.Status == 1;
where &= User._.CreateTime >= DateTime.Today;
if (!key.IsNullOrEmpty()) where &= User._.Name.Contains(key);
var list2 = User.FindAll(where, page);

// 统计
var count = User.FindCount(User._.Status == 1);

// 查询最大/最小值
var maxId = User.FindMax(User._.Id, null);
```

### 5.2.1 字段表达式方法参考

`FieldItem`（`Entity._.FieldName`）提供丰富的表达式方法，可直接用于 `WhereExpression` 或 `FindAll` 条件：

| 方法 | 说明 | 生成 SQL 示例 |
|------|------|------|
| `_.Name == value` | 等于 | `Name = 'test'` |
| `_.Name != value` | 不等于 | `Name <> 'test'` |
| `_.Id > value` | 大于 | `Id > 10` |
| `_.Id >= value` | 大于等于 | `Id >= 10` |
| `_.Id < value` | 小于 | `Id < 100` |
| `_.Id <= value` | 小于等于 | `Id <= 100` |
| `_.Name.Contains("x")` | 包含 | `Name Like '%x%'` |
| `_.Name.NotContains("x")` | 不包含 | `Name Not Like '%x%'` |
| `_.Name.StartsWith("x")` | 开头 | `Name Like 'x%'` |
| `_.Name.EndsWith("x")` | 结尾 | `Name Like '%x'` |
| `_.Id.In(list)` | In 操作 | `Id In(1,2,3)` |
| `_.Id.NotIn(list)` | Not In | `Id Not In(1,2,3)` |
| `_.Name.IsNull()` | 是否 NULL | `Name Is Null` |
| `_.Name.NotIsNull()` | 不为 NULL | `Name Is Not Null` |
| `_.Name.IsNullOrEmpty()` | NULL 或空串（仅 String） | `(Name Is Null Or Name='')` |
| **`_.Name.NotIsNullOrEmpty()`** | **不为 NULL 且不为空串**（仅 String） | `(Name Is Not Null And Name<>'')` |
| `_.Flag.IsTrue(true)` | 布尔真值 | `Flag=True` |
| `_.Flag.IsTrue(false)` | 布尔假值/NULL | `Flag<>True Or Flag Is Null` |
| `_.Id.Asc()` | 升序排序 | `Id Asc` |
| `_.Id.Desc()` | 降序排序 | `Id Desc` |

**空值判断常见写法**：
```csharp
// ✅ 推荐：使用内置方法
exp &= _.DevName.NotIsNullOrEmpty();  // 字段不为空且不为空串

// ❌ 不推荐：手写两个条件
exp &= _.DevName != "" & _.DevName != null;
```

**注意**：`IsNullOrEmpty()` / `NotIsNullOrEmpty()` 仅支持 `String` 类型字段，非字符串字段请使用 `IsNull()` / `NotIsNull()`。

### 5.3 批量操作

```csharp
// 批量插入
var list = new List<User>();
for (var i = 0; i < 100; i++)
{
    list.Add(new User { Name = $"user{i}" });
}
list.Insert();

// 批量更新（将 Status==1 的记录改为 Status=2）
User.Update(User._.Status == 2, User._.Status == 1);

// 批量删除
User.Delete(User._.Status == 0);
```

### 5.4 异步操作

```csharp
var user = await User.FindAsync(User._.Id == 1);
var list = await User.FindAllAsync(User._.Status == 1, page);
await entity.InsertAsync();
await entity.SaveAsync();  // 异步保存，用于日志等高频写入
```

### 5.5 缓存查询

```csharp
// 实体缓存（适用于小表）
var list = User.FindAllWithCache();

// 单对象缓存（按主键）
var user = User.FindByKeyWithCache(1);
```

### 5.6 Biz 文件数据层逻辑规范

**核心理念**：所有需要人工编写的数据层逻辑代码，一律放在实体类的 Biz 文件（`*.Biz.cs`）中，包括**高级查询**（`#region 高级查询`）与**添删改查重载**等。外部调用方只传语义化参数，不感知 `WhereExpression` 拼接细节。

#### 高级查询封装选择

| 场景 | 方法形式 | 说明 | 示例 |
|------|---------|------|------|
| 返回单个对象，参数 ≤2 个 | `FindByXxx` | 未查到时返回 `null` | `FindByUserId(userId)` |
| 返回列表，参数 ≤2 个，无模糊查询、无分页 | `FindAllByXxx` / `FindAllByXxxAndYyy` | 未查到时返回空列表，**不返回 null** | `FindAllByUserId(userId)` |
| 参数较多，或含模糊查询，或含分页 | `Search(...)` | 未查到时返回空列表，**不返回 null** | `Search(userId, key, page)` |
| 实体缓存内过滤（`Meta.Cache.FindAll(...)`） | `FindAllCachedXxx` / `FindCachedXxx` | — | `FindAllCachedEnabled()` / `FindCachedByQuestion(q)` |

**命名约定说明**：
- `FindByXxx`：返回**单个对象**（`TEntity?`），语义为"按条件查找一条记录"，未找到返回 `null`
- `FindAllByXxx`：返回**对象列表**（`IList<TEntity>`），语义为"按条件查找所有匹配记录"，结果为空时返回空列表而非 `null`
- `Search`：同样返回**对象列表**，结果为空时返回空列表而非 `null`

#### Search 方法签名约定

参数顺序（由左到右，按重要程度）：

```
Search(业务过滤字段..., DateTime start, DateTime end, String? key, PageParameter page)
```

- 时间区间 `(DateTime start, DateTime end)` 放在 key / page 左边
- 模糊查询关键词 `String? key` 放在 page 左边（倒数第二）
- 分页参数 `PageParameter page` 始终最后

#### 表达式简写

在 Biz 文件的静态方法内部，可**省略类名前缀**：

```csharp
// ✅ 推荐（Biz 文件内部）
var exp = _.UserId == userId;
if (!keyword.IsNullOrEmpty()) exp &= _.Title.Contains(keyword.Trim());
return FindAll(exp, page);

// ❌ 避免（外部业务代码中拼接表达式）
var exp = Conversation._.UserId == userId;
if (!keyword.IsNullOrEmpty()) exp &= Conversation._.Title.Contains(keyword.Trim());
var list = Conversation.FindAll(exp, p);
```

#### 示例

```csharp
// Biz 文件内 #region 高级查询

/// <summary>根据用户编号查找最新一条会话</summary>
/// <param name="userId">用户编号</param>
/// <returns>会话对象，不存在时返回 null</returns>
public static Conversation? FindByUserId(Int32 userId) => Find(_.UserId == userId);

/// <summary>根据用户编号查找所有会话</summary>
/// <param name="userId">用户编号</param>
/// <returns>会话列表，不存在时返回空列表</returns>
public static IList<Conversation> FindAllByUserId(Int32 userId) => FindAll(_.UserId == userId);

/// <summary>分页搜索用户会话列表</summary>
/// <param name="userId">用户编号</param>
/// <param name="keyword">标题关键字，为空时不过滤</param>
/// <param name="page">分页参数</param>
/// <returns>会话列表，不存在时返回空列表</returns>
public static IList<Conversation> Search(Int32 userId, String? keyword, PageParameter page)
{
    var exp = new WhereExpression();
    exp &= _.UserId == userId;
    if (!keyword.IsNullOrEmpty()) exp &= _.Title.Contains(keyword.Trim());

    return FindAll(exp, page);
}
```

---

## 6. 运行时机制

### 6.1 实体拦截器（自动填充字段）

XCode 内置全局拦截器，实体包含特定命名字段时自动触发，**无需业务代码手动赋值**：

| 拦截器 | 匹配字段名 | 字段类型 | 行为 |
|--------|-----------|---------|------|
| `TimeInterceptor` | `CreateTime` | `DateTime` | Insert 时自动填充当前时间 |
| | `UpdateTime` | `DateTime` | Insert/Update 时自动填充当前时间 |
| `UserInterceptor` | `CreateUserID` | `Int32`/`Int64` | Insert 时填充当前用户 ID |
| | `CreateUser` | `String` | Insert 时填充当前用户名 |
| | `UpdateUserID` | `Int32`/`Int64` | Insert/Update 时填充当前用户 ID |
| | `UpdateUser` | `String` | Insert/Update 时填充当前用户名 |
| `IPInterceptor` | `CreateIP` | `String` | Insert 时填充客户端 IP |
| | `UpdateIP` | `String` | Insert/Update 时填充客户端 IP |
| `TraceInterceptor` | `TraceId` | `String` | Insert/Update 时填充链路追踪 ID |

**建模约定**：这些自动填充字段通常设置 `Category="扩展"` + `Model="False"`，不暴露到模型类中。

示例（Model.xml 中的扩展字段标准写法）：
```xml
<Column Name="CreateUser" DataType="String" Description="创建者" Model="False" Category="扩展" />
<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="UpdateUser" 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="TraceId" DataType="String" Description="链路追踪" Model="False" Category="扩展" />
```

### 6.2 反向工程（自动建表）

XCode 启动时自动对比实体模型与数据库表结构，根据 `Migration` 配置决定行为：

| 模式 | 说明 | 适用场景 |
|------|------|---------|
| `Off` | 关闭，不检查不执行 | 生产环境（表结构由 DBA 管理） |
| `ReadOnly` | 只读，检查差异但不执行 DDL | 生产环境排查 |
| `On` | 打开，仅新建表/列（默认值） | 开发/测试环境 |
| `Full` | 完全，可修改列类型、删除列/索引 | 开发初期快速迭代 |

### 6.3 XCodeSetting 配置

通过配置文件 `XCode.json` 或 `appsettings.json` 的 `XCode` 节控制运行时行为：

| 配置项 | 默认值 | 说明 |
|--------|--------|------|
| `Debug` | `true` | 是否启用调试日志 |
| `ShowSQL` | `true` | 是否输出 SQL 语句 |
| `SQLPath` | `""` | SQL 日志独立目录，生产环境建议设置 |
| `TraceSQLTime` | `1000` | SQL 慢查询阈值（毫秒） |
| `UseParameter` | `false` | 参数化添删改查 |
| `CommandTimeout` | `0` | 命令超时（秒），0 不限制 |
| `RetryOnFailure` | `0` | 失败重试次数 |
| `Migration` | `On` | 反向工程模式（见 6.2） |
| `BatchSize` | `5000` | 批量操作数据量 |
| `EntityCacheExpire` | `10` | 实体缓存过期时间（秒） |
| `SingleCacheExpire` | `10` | 单对象缓存过期时间（秒） |

**生产环境建议**：
```json
{
  "XCode": {
    "Migration": "Off",
    "ShowSQL": false,
    "SQLPath": "../SqlLog",
    "TraceSQLTime": 500
  }
}
```

---

## 7. 多模块项目结构

对于复杂业务系统，建议按模块组织：

```
Zero.Data/
├── Order/           # 订单模块
│   ├── Order.xml    # 订单模型
│   ├── 订单.cs
│   └── 订单明细.cs
├── Product/         # 商品模块
│   ├── Product.xml  # 商品模型
│   ├── 商品.cs
│   └── 分类.cs
└── Member/          # 会员模块
    ├── Member.xml   # 会员模型
    └── 会员.cs
```

每个模块目录内有独立的 `*.xml` 模型文件，在各自目录执行 `xcode` 命令生成实体类。

---

## 8. xcode 命令参考

```powershell
# 在模型文件所在目录执行（自动查找所有 *.xml）
xcode

# 指定模型文件
xcode Model.xml
xcode Order.xml
```

**执行效果**：
1. 读取 XML 模型文件
2. 生成实体类（`*.cs`）
3. 生成模型类（如配置了 `ModelClass`）
4. 生成接口（如配置了 `ModelInterface`）
5. 生成数据字典（`*.htm`）
6. 生成魔方控制器（如配置了 `CubeOutput`）

---

## 9. 常见问题

### 9.1 模型文件命名

- 默认：`Model.xml`
- 推荐：`{系统英文名}.xml` 或 `{模块名}.xml`
- 复杂项目：每个模块目录一个模型文件

### 9.2 实体类生成位置

- 实体类生成在 `xcode` 命令执行目录
- 可通过 `Output` 配置项指定输出目录
- 魔方控制器通过 `CubeOutput` 指定

### 9.3 数据库连接

在应用配置文件中配置连接字符串：

```json
{
  "ConnectionStrings": {
    "Order": "Server=.;Database=Order;Uid=sa;Pwd=xxx"
  }
}
```

连接名对应 Model.xml 中的 `ConnName`。未配置连接字符串时，默认创建同名 SQLite 数据库。

### 9.4 生成的代码能否手动修改

实体类分为两个文件：
- `实体名.cs`（如 `订单.cs`）：自动生成的数据映射代码，**每次 `xcode` 会覆盖，禁止手动修改**
- `实体名.Biz.cs`（如 `订单.Biz.cs`）：业务扩展代码，仅首次生成，**可自由修改**

需要调整字段、类型、索引时，应修改 `Model.xml` 后重新执行 `xcode`。

### 9.5 如何调试 SQL

配置 `XCodeSetting.ShowSQL = true`（默认开启），所有 SQL 输出到日志。设置 `SQLPath` 可将 SQL 日志独立存放。`TraceSQLTime` 控制慢查询阈值。

### 9.6 与 Cube 的协作

需要生成 Web 管理界面时：在 Model.xml 中配置 `CubeOutput` 指向 Web 项目的 Areas 目录，配置 `DisplayName` 作为区域名称，执行 `xcode` 自动生成控制器。深度定制见 `cube.instructions.md`。

---

## 10. Copilot 行为指引

### 10.1 数据建模时

1. **充分理解业务**：在设计表结构前，确保理解业务场景和数据关系
2. **合理设计主键**：
   - 普通表：`Int32` + `PrimaryKey="True" Identity="True"`
   - 大数据表：`Int64` + `PrimaryKey="True" DataScale="time"`（雪花 ID）
3. **必要的索引**：为查询条件字段添加索引
4. **字段长度**：String 类型必须指定合理的 `Length`
5. **扩展字段**：`CreateTime`/`UpdateTime`/`CreateUser`/`UpdateUser`/`CreateIP`/`UpdateIP` 等由拦截器自动填充（见 6.1），设置 `Model="False" Category="扩展"`

### 10.2 生成代码时

1. 确保在正确目录执行 `xcode`
2. 生成后检查编译是否通过
3. 如需修改生成的代码，应修改 Model.xml 后重新生成
4. 业务逻辑写在 `.Biz.cs` 文件中

### 10.3 边界意识

- 数据模型和实体操作 → 本指令
- Web 控制器和界面 → `cube.instructions.md`
- 基础编码规范 → `copilot-instructions.md`
