docs: README 模型字段去掉下划线前缀,DbContext 示例改用 prop 声明

This commit is contained in:
2026-08-19 09:19:25 +08:00
parent afa6096ed2
commit ab1bdce597
+27 -27
View File
@@ -28,13 +28,13 @@ import simcu::orm.*
@Table["users"] // 指定表名(不写则用类简单名)
public class User {
public var _id: Int64 = 0 // 整型 _id → 主键 + 数据库自增
public var _name: String = "" // 列名 name
public var id: Int64 = 0 // 整型 id → 主键 + 数据库自增
public var name: String = "" // 列名 name
@Column["full_name"]
public var _alias: String = "" // 注解覆盖列名
public var alias: String = "" // 注解覆盖列名
@Ignore
public var _temp: String = "" // 不映射
public var _age: Int32 = 0
public var temp: String = "" // 不映射
public var age: Int32 = 0
}
```
@@ -50,8 +50,8 @@ import simcu::orm.macros.*
@DbContext
public class AppDbContext {
public var users: DbSet<User>
public var orders: DbSet<Order>
prop users: DbSet<User>
prop orders: DbSet<Order>
}
main() {
@@ -60,19 +60,19 @@ main() {
// 2. 增
let user = User()
user._name = "alice"
user.name = "alice"
db.users.add(user) // 入队 INSERT
db.saveChanges() // 事务内执行,回读自增主键到 user._id
db.saveChanges() // 事务内执行,回读自增主键到 user.id
// 3. 改
user._age = 30
user.age = 30
db.users.update(user) // 入队 UPDATE(全部非主键列)
db.saveChanges()
// 4. 查
let list = db.users.query()
.filter("_age", ">", Int64(18)) // 属性名/列名自动映射列名
.orderBy("_name")
.filter("age", ">", Int64(18)) // 属性名/列名自动映射列名
.orderBy("name")
.skip(0).take(10)
.toList() // ArrayList<User>
let one = db.users.find(Int64(1)) // ?User,按主键
@@ -84,7 +84,7 @@ main() {
}
```
> 不用宏时手动继承 `DbContext` 等价写法:补 `public init(...) { super(...) }` 构造,每个 DbSet 写成 `public prop users: DbSet<User> { get() { this.set<User>() } }`,并 override `migrations()`。宏就是把这几个样板步骤自动做完(详见「模块说明 3」)。
> 不用宏时手动继承 `DbContext` 等价写法:补 `public init(...) { super(...) }` 构造,每个 DbSet 声明为 `public prop users: DbSet<User> { get() { this.set<User>() } }`,并 override `migrations()`。宏就是把这几个样板步骤自动做完(详见「模块说明 3」)。
### 3. 迁移
@@ -140,7 +140,7 @@ main() {
// 2. 模型变更后:旧模型快照(上次的 models) vs 新模型 → 增量迁移(表/列增删改)
let models2 = ArrayList<EntityModel>()
models2.add(ModelCache.get<User>()) // 假设 User 新增了 _age 字段
models2.add(ModelCache.get<User>()) // 假设 User 新增了 age 字段
models2.add(ModelCache.get<Product>())
let m1 = gen.diff("20250801000000_AddAge", "新增 age 列", models, models2)
Migrator(datasource).migrate([m1]) // 旧模型列表 models 由调用方保存,充当快照
@@ -187,8 +187,8 @@ import myapp.migrations.* // 注册文件所在子包(仅 import 触
@DbContext
public class MyDbContext {
public var users: DbSet<User>
public var orders: DbSet<Order>
prop users: DbSet<User>
prop orders: DbSet<Order>
}
main(args: Array<String>) {
@@ -257,8 +257,8 @@ orm-cj/
|------|-----------|------|------|
| `@Table["users"]` | `[Table("users")]` | 类 | 指定表名 |
| `@Column["full_name"]` | `[Column("full_name")]` | 字段 | 指定列名 |
| `@Key` | `[Key]` | 字段 | 标记主键(字段名 `_id` 自动为主键) |
| `@AutoIncrement` | `[DatabaseGenerated(Identity)]` | 字段 | 整型主键自增(整型 `_id` 默认自增) |
| `@Key` | `[Key]` | 字段 | 标记主键(字段名 `id` / `_id` 自动为主键) |
| `@AutoIncrement` | `[DatabaseGenerated(Identity)]` | 字段 | 整型主键自增(整型 `id` 默认自增) |
| `@Ignore` | `[NotMapped]` | 字段 | 不映射该字段 |
| `@Required` | `[Required]` | 字段 | 非空列(仅影响建表 DDL) |
| `@MaxLength[100]` | `[MaxLength(100)]` | 字段 | 字符串列最大长度(仅影响建表 DDL) |
@@ -266,9 +266,9 @@ orm-cj/
### 2. 模型映射约定(对齐 EF Core 数据模型)
- **表名**`@Table` 优先,否则类简单名;
- **列名**`@Column` 优先,否则按 `ColumnNamingPolicy`(默认 `StripUnderscore``_id``id`;可切换 `SnakeCase``_userName``user_name``Keep` 原样);
- **主键**`@Key` 标注,或字段名 `_id`v1 仅支持**单主键**
- **自增**`@AutoIncrement`,或整型(Int8-64`_id` 主键默认自增;INSERT 跳过该列并通过 `RETURNING` 回读;
- **列名**`@Column` 优先,否则按 `ColumnNamingPolicy`(默认 `StripUnderscore``_id``id``id` 原样;可切换 `SnakeCase``userName``user_name``Keep` 原样);
- **主键**`@Key` 标注,或字段名 `_id` / `id`v1 仅支持**单主键**
- **自增**`@AutoIncrement`,或整型(Int8-64`id` 主键默认自增;INSERT 跳过该列并通过 `RETURNING` 回读;
- **客户端生成主键**`String` 主键默认客户端生成(`GuidUtil`:时间戳 + 自增序号 hex),INSERT 时为空自动生成;
- **实体要求**:字段必须是 `public var` 标量类型,且提供无参 `public init()`
@@ -276,7 +276,7 @@ orm-cj/
### 3. DbContext / DbSet(对齐 EF Core
**推荐:`@DbContext` 宏**。把 `DbSet` 声明为属性(字段也行),宏自动补继承/构造/注入/`migrations()`
**推荐:`@DbContext` 宏**。把 `DbSet` 声明为 `prop`,宏自动补继承/构造/注入/`migrations()`
```cangjie
import simcu::orm.*
@@ -286,8 +286,8 @@ import std.collection.* // migrations() 签名需要 ArrayList
@DbContext
public class AppDbContext {
public var users: DbSet<User>
public var orders: DbSet<Order>
prop users: DbSet<User>
prop orders: DbSet<Order>
}
// 用法(宏生成 (driverName, connStr) 构造)
@@ -344,12 +344,12 @@ public class AppDbContext <: DbContext {
```cangjie
let qb = db.users.query() // 宏方式直接 db.users;等价 db.set<User>().query()
qb.filter("_age", ">", Int64(18)) // (属性名, 操作符, 值):自动映射列名
qb.filter("age", ">", Int64(18)) // (属性名, 操作符, 值):自动映射列名
let ps = ArrayList<Any>() // (SQL 片段, 参数):按 ? 顺序,写原始列名
ps.add(Int64(18))
ps.add(true)
qb.filter("age > ? AND active = ?", ps)
qb.orderBy("_name").orderByDesc("_age") // 排序
qb.orderBy("name").orderByDesc("age") // 排序
qb.skip(10).take(5) // 分页(LIMIT/OFFSET
qb.toList() // ArrayList<User>
qb.first() // ?User
@@ -379,7 +379,7 @@ cjpm test # 纯逻辑单元测试(模型映射/SQL 生成/DDL 生成/QueryB
## 已知限制(v1
- **cjc 1.1.3 编译器缺陷(重要)**:类上带 `@Table[...]` 注解时,若成员变量带 ≥2 个注解且用 `= ""` 做空字符串初始化(如 `@Required @MaxLength[100] public var _x: String = ""`),编译报 `expected expression after '=', found '<EOF>'`。规避:默认值改用 `= String()` 或直接省略初始化器。`orm-cj` 包内代码与 e2e 示例均按此规避写法;
- **cjc 1.1.3 编译器缺陷(重要)**:类上带 `@Table[...]` 注解时,若成员变量带 ≥2 个注解且用 `= ""` 做空字符串初始化(如 `@Required @MaxLength[100] public var x: String = ""`),编译报 `expected expression after '=', found '<EOF>'`。规避:默认值改用 `= String()` 或直接省略初始化器。`orm-cj` 包内代码与 e2e 示例均按此规避写法;
- **仅单主键**;不支持复合主键;
- **不支持 Option 字段**`?String` 等请改用具体标量类型)与**父类字段**(不扫描继承字段);
- 不支持导航属性 / 延迟加载 / 级联删除(对齐 EF Core 这些能力属于 v2+);