diff --git a/README.md b/README.md index 2a0788b..a2ae522 100644 --- a/README.md +++ b/README.md @@ -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 - public var orders: DbSet + prop users: DbSet + prop orders: DbSet } 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 let one = db.users.find(Int64(1)) // ?User,按主键 @@ -84,7 +84,7 @@ main() { } ``` -> 不用宏时手动继承 `DbContext` 等价写法:补 `public init(...) { super(...) }` 构造,每个 DbSet 写成 `public prop users: DbSet { get() { this.set() } }`,并 override `migrations()`。宏就是把这几个样板步骤自动做完(详见「模块说明 3」)。 +> 不用宏时手动继承 `DbContext` 等价写法:补 `public init(...) { super(...) }` 构造,每个 DbSet 声明为 `public prop users: DbSet { get() { this.set() } }`,并 override `migrations()`。宏就是把这几个样板步骤自动做完(详见「模块说明 3」)。 ### 3. 迁移 @@ -140,7 +140,7 @@ main() { // 2. 模型变更后:旧模型快照(上次的 models) vs 新模型 → 增量迁移(表/列增删改) let models2 = ArrayList() - models2.add(ModelCache.get()) // 假设 User 新增了 _age 字段 + models2.add(ModelCache.get()) // 假设 User 新增了 age 字段 models2.add(ModelCache.get()) 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 - public var orders: DbSet + prop users: DbSet + prop orders: DbSet } main(args: Array) { @@ -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 - public var orders: DbSet + prop users: DbSet + prop orders: DbSet } // 用法(宏生成 (driverName, connStr) 构造) @@ -344,12 +344,12 @@ public class AppDbContext <: DbContext { ```cangjie let qb = db.users.query() // 宏方式直接 db.users;等价 db.set().query() -qb.filter("_age", ">", Int64(18)) // (属性名, 操作符, 值):自动映射列名 +qb.filter("age", ">", Int64(18)) // (属性名, 操作符, 值):自动映射列名 let ps = ArrayList() // (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 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 ''`。规避:默认值改用 `= String()` 或直接省略初始化器。`orm-cj` 包内代码与 e2e 示例均按此规避写法; +- **cjc 1.1.3 编译器缺陷(重要)**:类上带 `@Table[...]` 注解时,若成员变量带 ≥2 个注解且用 `= ""` 做空字符串初始化(如 `@Required @MaxLength[100] public var x: String = ""`),编译报 `expected expression after '=', found ''`。规避:默认值改用 `= String()` 或直接省略初始化器。`orm-cj` 包内代码与 e2e 示例均按此规避写法; - **仅单主键**;不支持复合主键; - **不支持 Option 字段**(`?String` 等请改用具体标量类型)与**父类字段**(不扫描继承字段); - 不支持导航属性 / 延迟加载 / 级联删除(对齐 EF Core 这些能力属于 v2+);