学习ORMX的CRUD操作,包括数据的插入、查询、更新和删除,以及MongoDB特定的操作。 关键字:CRUD操作, 插入数据, 查询数据, 更新数据, 删除数据, MongoDB操作
第六章:CRUD操作
6.1 Create(插入数据)
6.1.1 单个插入
使用 Insert 方法插入单个实体:
using var userTable = tableManager.Table<User>();
var user = new User
{
Name = "张三",
Email = "zhangsan@example.com",
Age = 25
};
var insertedUser = userTable.Insert(user);
Console.WriteLine(<div class="latex">$"插入成功,ID: {insertedUser.Id}");
说明:
Insert方法会自动生成 INSERT 语句- 如果主键是自增的,插入后会自动填充 ID 值
- 返回的实体包含数据库生成的值(如自增 ID)
6.1.2 批量插入
使用 InsertAll 方法批量插入多个实体:
using var userTable = tableManager.Table<User>();
var users = new List<User>
{
new User { Name = "张三", Email = "zhangsan@example.com", Age = 25 },
new User { Name = "李四", Email = "lisi@example.com", Age = 30 },
new User { Name = "王五", Email = "wangwu@example.com", Age = 28 }
};
var insertedUsers = userTable.InsertAll(users);
Console.WriteLine($</div>"批量插入了 {insertedUsers.Count} 个用户");
说明:
InsertAll方法会生成批量 INSERT 语句- 性能优于逐个插入,适合大量数据
- 返回的实体列表包含数据库生成的值
6.1.3 插入注意事项
主键处理
- 如果主键是自增的,不需要设置 ID 值
- 如果主键不是自增的,需要手动设置 ID 值
可空字段
- 可空字段可以不设置值
- 不可空字段必须设置值
默认值
- 如果字段有默认值,可以不设置该字段的值
- 数据库会使用默认值
数据类型
- 确保数据类型与数据库列类型匹配
- ORMX 会自动进行类型转换
6.1.4 MongoDB 特定的插入操作
MongoDB 插入特点:
- MongoDB 使用
_id字段作为主键,ORMX 会自动映射到实体的Id属性 - 对于整数类型的
Id,ORMX 会自动转换为 MongoDB 的ObjectId或保持为整数 - 插入操作会返回包含完整
Id值的实体
MongoDB 插入示例:
using JCode.ORMX.DbProvider.MongoDB;
// 创建 MongoDB 提供程序
using var provider = new MongoDBProvider("mongodb://localhost:27017", "mydb");
var tableManager = provider.GetTableManager();
// 获取表对象
var userTable = tableManager.Table<User>();
// 单个插入
var user = new User
{
Name = "张三",
Email = "zhangsan@example.com",
Age = 25,
CreatedAt = DateTime.Now,
IsActive = true
};
var insertedUser = userTable.Insert(user);
Console.WriteLine(<div class="latex">$"插入成功,ID: {insertedUser.Id}");
// 批量插入
var users = new List<User>
{
new User { Name = "李四", Email = "lisi@example.com", Age = 30 },
new User { Name = "王五", Email = "wangwu@example.com", Age = 28 }
};
var insertedUsers = userTable.InsertAll(users);
Console.WriteLine($</div>"批量插入了 {insertedUsers.Count} 个用户");
foreach (var u in insertedUsers)
{
Console.WriteLine(<div class="latex">$" - {u.Name}, ID: {u.Id}");
}
MongoDB 插入注意事项:
- _id 字段映射:实体的
Id属性会自动映射到 MongoDB 的_id字段 - 类型转换:ORMX 会根据
Id属性的类型自动选择合适的 MongoDB 类型 - 批量操作:批量插入在 MongoDB 中性能优于单个插入
- 会话支持:在事务中,插入操作会使用 MongoDB 会话
关于实体映射的详细说明,请查阅实体映射。
6.2 Read(查询数据)
6.2.1 根据 ID 查找
使用 Where 方法结合 FirstOrDefault 根据主键查找单个实体:
using var userTable = tableManager.Table<User>();
var user = userTable.Where(u => u.Id == 1).FirstOrDefault();
if (user != null)
{
Console.WriteLine($</div>"找到用户: {user.Name}, 邮箱: {user.Email}");
}
else
{
Console.WriteLine("用户不存在");
}
说明:
Where方法用于设置查询条件FirstOrDefault方法返回第一个匹配的实体,如果找不到返回null- 适用于主键查询场景
6.2.2 查找所有数据
使用 GetList 方法查找所有实体:
using var userTable = tableManager.Table<User>();
var users = userTable.GetList();
Console.WriteLine(<div class="latex">$"总共有 {users.Count} 个用户");
foreach (var user in users)
{
Console.WriteLine($</div>"ID: {user.Id}, 姓名: {user.Name}, 邮箱: {user.Email}");
}
说明:
GetList方法返回所有实体- 返回类型为
List<T> - 适用于数据量不大的场景
6.2.3 类型映射
ORMX 会自动将数据库类型映射到 C# 类型:
// 数据库类型 -> C# 类型
INTEGER -> int
TEXT -> string
REAL -> double
BLOB -> byte[]
DATETIME -> DateTime
BOOLEAN -> bool
示例:
public class User
{
[Column(IsPrimaryKey = true, IsAutoIncrement = true)]
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
public DateTime CreatedAt { get; set; }
public bool IsActive { get; set; }
}
// 查询时自动映射
var user = userTable.Where(u => u.Id == 1).FirstOrDefault();
Console.WriteLine(user.CreatedAt); // DateTime 类型
Console.WriteLine(user.IsActive); // bool 类型
6.2.4 MongoDB 特定的查询操作
MongoDB 查询特点:
- MongoDB 使用文档查询语法,ORMX 会自动将 LINQ 查询转换为 MongoDB 查询
- 支持基本的比较操作符(==, !=, >, <, >=, ⇐)
- 支持逻辑操作符(&&, ||, !)
- 支持字符串操作(Contains, StartsWith, EndsWith)
MongoDB 查询示例:
using JCode.ORMX.DbProvider.MongoDB;
// 创建 MongoDB 提供程序
using var provider = new MongoDBProvider("mongodb://localhost:27017", "mydb");
var tableManager = provider.GetTableManager();
// 获取表对象
var userTable = tableManager.Table<User>();
// 根据 ID 查询
var userById = userTable.Where(u => u.Id == 1).FirstOrDefault();
if (userById != null)
{
Console.WriteLine(<div class="latex">$"找到用户: {userById.Name}");
}
// 条件查询
var activeUsers = userTable.Where(u => u.IsActive == true && u.Age > 18).GetList();
Console.WriteLine($</div>"找到 {activeUsers.Count} 个活跃用户");
// 字符串查询
var usersWithEmail = userTable.Where(u => u.Email.Contains("example.com")).GetList();
Console.WriteLine(<div class="latex">$"找到 {usersWithEmail.Count} 个使用 example.com 邮箱的用户");
// 排序查询
var sortedUsers = userTable.Where(u => u.Age > 20).OrderByDescending(u => u.Age).GetList();
Console.WriteLine("按年龄降序排列的用户:");
foreach (var u in sortedUsers)
{
Console.WriteLine($</div>" - {u.Name}, 年龄: {u.Age}");
}
// 分页查询
var pagedUsers = userTable.Where(u => u.IsActive == true)
.OrderBy(u => u.Name)
.Offset(0)
.Limit(10)
.GetList();
Console.WriteLine("第 1 页用户(10 个):");
foreach (var u in pagedUsers)
{
Console.WriteLine(<div class="latex">$" - {u.Name}");
}
MongoDB 查询注意事项:
- 字段映射:ORMX 会自动处理实体属性到 MongoDB 字段的映射
- 类型转换:自动处理 C# 类型到 MongoDB BSON 类型的转换
- 查询优化:对于频繁查询的字段,建议在 MongoDB 中创建索引
- 复杂查询:复杂的 LINQ 查询可能无法完全转换为 MongoDB 查询语法
关于查询构建的详细说明,请参考查询构建。
6.3 Update(更新数据)
6.3.1 单个更新
使用 Update 方法更新单个实体:
using var userTable = tableManager.Table<User>();
// 先查询
var user = userTable.Where(u => u.Id == 1).FirstOrDefault();
if (user != null)
{
// 修改属性
user.Age = 26;
user.Email = "newemail@example.com";
// 更新
userTable.Update(user);
Console.WriteLine("更新成功");
}
说明:
Update方法会根据主键生成 UPDATE 语句- 只更新修改过的字段
- 返回受影响的行数
6.3.2 批量更新
使用 UpdateAll 方法批量更新多个实体:
using var userTable = tableManager.Table<User>();
// 查询所有用户
var users = userTable.GetList();
// 修改所有用户的年龄
foreach (var user in users)
{
user.Age += 1;
}
// 批量更新
userTable.UpdateAll(users);
Console.WriteLine($</div>"批量更新了 {users.Count} 个用户");
说明:
UpdateAll方法会生成批量 UPDATE 语句- 性能优于逐个更新
- 适合批量修改数据的场景
6.3.3 类型安全的字段更新
使用 Update 方法的重载,可以只更新指定字段:
using var userTable = tableManager.Table<User>();
// 只更新 Age 字段
userTable.Update(1, new { Age = 30 });
// 更新多个字段
userTable.Update(1, new { Age = 30, Email = "updated@example.com" });
说明:
- 使用匿名对象指定要更新的字段
- 只更新指定的字段,其他字段保持不变
- 类型安全,编译时检查
6.3.4 更新注意事项
主键不能修改
- 更新时不能修改主键值
- 如果需要修改主键,需要先删除再插入
并发控制
- ORMX 不提供自动的并发控制
- 需要手动实现乐观锁或悲观锁
部分更新
- 如果只需要更新部分字段,使用匿名对象更新
- 避免加载整个实体再更新
6.3.5 MongoDB 特定的更新操作
MongoDB 更新特点:
- MongoDB 使用
updateOne或updateMany操作 - ORMX 会自动根据实体的
Id字段定位文档 - 支持部分字段更新,只更新修改过的字段
MongoDB 更新示例:
using JCode.ORMX.DbProvider.MongoDB;
// 创建 MongoDB 提供程序
using var provider = new MongoDBProvider("mongodb://localhost:27017", "mydb");
var tableManager = provider.GetTableManager();
// 获取表对象
var userTable = tableManager.Table<User>();
// 单个更新
var user = userTable.Where(u => u.Id == 1).FirstOrDefault();
if (user != null)
{
// 修改属性
user.Age = 26;
user.Email = "newemail@example.com";
user.IsActive = true;
// 更新
var affectedRows = userTable.Update(user);
Console.WriteLine(<div class="latex">$"更新成功,影响行数:{affectedRows}");
}
// 批量更新(使用条件)
var updateCount = userTable.Where(u => u.Age < 18).Update(u => new User { IsActive = false });
Console.WriteLine($</div>"批量更新了 {updateCount} 个用户");
// 部分字段更新
var partialUpdateCount = userTable.Update(1, new { Age = 27, Email = "updated@example.com" });
Console.WriteLine(<div class="latex">$"部分更新成功,影响行数:{partialUpdateCount}");
MongoDB 更新注意事项:
- _id 字段:更新操作会使用
_id字段定位文档,确保实体包含正确的Id值 - 字段映射:ORMX 会自动处理实体属性到 MongoDB 字段的映射
- 类型转换:自动处理 C# 类型到 MongoDB BSON 类型的转换
- 性能考虑:对于大量数据的更新,建议使用批量更新操作
6.4 Delete(删除数据)
6.4.1 单个删除
使用 Delete 方法删除单个实体:
using var userTable = tableManager.Table<User>();
// 先查询要删除的实体
var user = userTable.Where(u => u.Id == 1).FirstOrDefault();
if (user != null)
{
var affectedRows = userTable.Delete(user);
Console.WriteLine($</div>"删除成功,影响行数:{affectedRows}");
}
else
{
Console.WriteLine("删除失败,用户不存在");
}
说明:
Delete方法接受实体对象作为参数- 返回影响的行数
- 如果找不到记录,返回 0
6.4.2 批量删除
使用 DeleteAll 方法批量删除多个实体:
using var userTable = tableManager.Table<User>();
// 查询要删除的用户
var users = userTable.Where(u => u.Age < 18).GetList();
// 批量删除
var deletedCount = userTable.DeleteAll(users);
Console.WriteLine(<div class="latex">$"批量删除了 {deletedCount} 个用户");
说明:
DeleteAll方法会生成批量 DELETE 语句- 性能优于逐个删除
- 适合批量删除数据的场景
6.4.3 根据条件删除
使用 Delete 方法配合 Where 条件删除:
using var userTable = tableManager.Table<User>();
// 删除年龄小于 18 的用户
var deletedCount = userTable.Where(u => u.Age < 18).Delete();
Console.WriteLine($</div>"删除了 {deletedCount} 个用户");
说明:
- 使用 Where 方法指定删除条件
- 类型安全,编译时检查
- 返回删除的记录数
6.4.4 清空表
使用 Truncate 方法清空表:
using var userTable = tableManager.Table<User>();
var success = userTable.Truncate();
if (success)
{
Console.WriteLine("表已清空");
}
说明:
Truncate方法会删除表中的所有数据- 比逐个删除更高效
- 会重置自增 ID
6.4.5 删除表
使用 Drop 方法删除表:
using var userTable = tableManager.Table<User>();
var success = userTable.Drop();
if (success)
{
Console.WriteLine("表已删除");
}
说明:
Drop方法会删除整个表- 包括表结构和数据
- 慎用,不可恢复
6.4.6 删除注意事项
级联删除
- ORMX 不提供自动的级联删除
- 需要在数据库层面设置外键约束
软删除
- 如果需要软删除,可以添加
IsDeleted字段 - 使用更新操作代替删除操作
- 如果需要软删除,可以添加
事务保护
- 删除操作应该在事务中执行
- 确保数据一致性
6.4.7 MongoDB 特定的删除操作
MongoDB 删除特点:
- MongoDB 使用
deleteOne或deleteMany操作 - ORMX 会自动根据实体的
Id字段定位文档 - 支持条件删除多个文档
MongoDB 删除示例:
using JCode.ORMX.DbProvider.MongoDB;
// 创建 MongoDB 提供程序
using var provider = new MongoDBProvider("mongodb://localhost:27017", "mydb");
var tableManager = provider.GetTableManager();
// 获取表对象
var userTable = tableManager.Table<User>();
// 单个删除
var user = userTable.Where(u => u.Id == 1).FirstOrDefault();
if (user != null)
{
var affectedRows = userTable.Delete(user);
Console.WriteLine(<div class="latex">$"删除成功,影响行数:{affectedRows}");
}
// 根据 ID 删除
var deletedById = userTable.DeleteById(2);
Console.WriteLine($</div>"根据 ID 删除,影响行数:{deletedById}");
// 批量删除(使用条件)
var deleteCount = userTable.Where(u => u.Age < 18).Delete();
Console.WriteLine(<div class="latex">$"批量删除了 {deleteCount} 个用户");
MongoDB 删除注意事项:
- _id 字段:删除操作会使用
_id字段定位文档 - 条件删除:批量删除操作会转换为 MongoDB 的
deleteMany操作 - 性能考虑:对于大量数据的删除,建议分批删除或使用索引
- 事务支持:在事务中,删除操作会使用 MongoDB 会话
关于事务处理的详细用法,请查阅事务处理。
6.5 完整示例
6.5.1 用户管理系统
下面是一个完整的用户管理系统示例,演示所有 CRUD 操作:
using System;
using System.Collections.Generic;
using JCode.ORMX.Attributes;
using JCode.ORMX.DbProvider;
using JCode.ORMX.Core;
using Microsoft.Data.Sqlite;
// 定义实体类
[Table(Name = "Users")]
public class User
{
[Column(IsPrimaryKey = true, IsAutoIncrement = true)]
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
// 创建数据库提供程序(推荐方式)
using var provider = new SqliteDatabaseProvider("Data Source=:memory:");
var tableManager = provider.GetTableManager();
var userTable = tableManager.Table<User>();
// 1. 创建用户
Console.WriteLine("=== 创建用户 ===");
var users = new List<User>
{
new User { Name = "张三", Email = "zhangsan@example.com", Age = 25 },
new User { Name = "李四", Email = "lisi@example.com", Age = 30 },
new User { Name = "王五", Email = "wangwu@example.com", Age = 28 }
};
userTable.InsertAll(users);
Console.WriteLine($</div>"创建了 {users.Count} 个用户");
// 2. 查询所有用户
Console.WriteLine("\n=== 查询所有用户 ===");
var allUsers = userTable.GetList();
foreach (var user in allUsers)
{
Console.WriteLine(<div class="latex">$"ID: {user.Id}, 姓名: {user.Name}, 邮箱: {user.Email}, 年龄: {user.Age}");
}
// 3. 根据 ID 查找用户
Console.WriteLine("\n=== 根据 ID 查找用户 ===");
var user = userTable.Where(u => u.Id == 1).FirstOrDefault();
if (user != null)
{
Console.WriteLine($</div>"找到用户: {user.Name}, 邮箱: {user.Email}, 年龄: {user.Age}");
}
// 4. 更新用户
Console.WriteLine("\n=== 更新用户 ===");
user.Age = 26;
userTable.Update(user);
var updatedUser = userTable.Where(u => u.Id == 1).FirstOrDefault();
Console.WriteLine(<div class="latex">$"用户年龄已更新为: {updatedUser.Age}");
// 5. 删除用户
Console.WriteLine("\n=== 删除用户 ===");
var success = userTable.Delete(3);
if (success)
{
Console.WriteLine("用户删除成功");
}
// 6. 查询剩余用户
Console.WriteLine("\n=== 查询剩余用户 ===");
var remainingUsers = userTable.GetList();
Console.WriteLine($</div>"剩余 {remainingUsers.Count} 个用户");
foreach (var remainingUser in remainingUsers)
{
Console.WriteLine(<div class="latex">$"ID: {remainingUser.Id}, 姓名: {remainingUser.Name}");
}
}
}
运行结果:
=== 创建用户 ===
创建了 3 个用户
=== 查询所有用户 ===
ID: 1, 姓名: 张三, 邮箱: zhangsan@example.com, 年龄: 25
ID: 2, 姓名: 李四, 邮箱: lisi@example.com, 年龄: 30
ID: 3, 姓名: 王五, 邮箱: wangwu@example.com, 年龄: 28
=== 根据 ID 查找用户 ===
找到用户: 张三, 邮箱: zhangsan@example.com, 年龄: 25
=== 更新用户 ===
用户年龄已更新为: 26
=== 删除用户 ===
用户删除成功
=== 查询剩余用户 ===
剩余 2 个用户
ID: 1, 姓名: 张三
ID: 2, 姓名: 李四
6.6 最佳实践
6.6.1 使用事务
对于涉及多个操作的场景,应该使用事务:
using var transaction = new Transaction(tableManager);
transaction.Begin(IsolationLevel.ReadCommitted);
try
{
userTable.Insert(user1);
userTable.Insert(user2);
userTable.Insert(user3);
transaction.Commit();
Console.WriteLine("所有操作成功提交");
}
catch (Exception ex)
{
transaction.Rollback();
Console.WriteLine($</div>"操作失败,已回滚: {ex.Message}");
}
关于事务处理的详细用法,请查阅事务处理。
6.6.2 批量操作优先
对于大量数据的操作,优先使用批量方法:
// 推荐:批量插入
userTable.InsertAll(users);
// 不推荐:逐个插入
foreach (var user in users)
{
userTable.Insert(user);
}
6.6.3 错误处理
始终进行错误处理:
try
{
userTable.Insert(user);
}
catch (Exception ex)
{
Console.WriteLine($"插入失败: {ex.Message}");
// 处理错误
}
6.6.4 资源管理
使用 using 语句管理资源:
using var userTable = tableManager.Table<User>();
// 使用表对象
// 自动释放资源
总结
本章介绍了 ORMX 框架的 CRUD 操作,包括数据的插入、查询、更新和删除。ORMX 提供了简洁的 API,支持单个操作和批量操作,能够满足大多数业务场景的需求。对于 MongoDB,ORMX 提供了专门的 CRUD 操作支持,包括 _id 字段映射、文档查询和批量操作等。合理使用批量操作可以显著提升性能,使用事务可以确保数据一致性。
扩展思考
在高并发场景下,如何处理数据的并发修改问题?是否需要引入乐观锁或悲观锁机制?对于大数据量的删除操作,如何避免锁表和性能问题?在分布式系统中,如何保证跨节点的数据一致性?这些问题值得在深入使用 ORMX 后进一步思考。