A:增加数据库配置和使用

This commit is contained in:
jimmy committed 2025-11-18 11:14:56 +08:00
1 parent 53d1dd2dbf
commit f7660c49e8
86 files changed
+7401 -271

No files matched your search

+452
View File
@@ -0,0 +1,452 @@
# Sharp.Data
让 EF Core 使用更简单的数据访问模块,提供开箱即用的仓储模式、审计、软删除等基础设施。
> **设计理念**:Data 模块专注于数据访问基础设施,不包含业务逻辑。实体基类是**可选的**,你可以使用自己的实体定义。
## 特性
- ✅ **极简 API** - 3 行代码启动,类似 NetServer 的设计理念
- ✅ **泛型仓储** - 提供常用 CRUD 操作,无需重复编写
- ✅ **自动审计** - 可选的审计功能,自动记录创建/修改信息
- ✅ **软删除** - 可选的软删除支持,逻辑删除而非物理删除
- ✅ **分页查询** - 复用 Common 模块的分页功能
- ✅ **多数据库** - 支持 SQLite、SQL Server、MySQL、PostgreSQL、InMemory
- ✅ **低耦合** - 仅依赖 EF Core 和 Common 模块
- ✅ **灵活扩展** - 所有功能都是可选的,按需启用
## 快速开始
### 1. 定义实体(可选使用基类)
```csharp
using Sharp.Data.Entities;
// 方式1:使用提供的基类(可选)
public class User : AuditableEntity // 包含审计和软删除
{
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
// 方式2:完全自定义(不使用基类)
public class Product
{
public Guid Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
}
```
### 2. 定义 DbContext
```csharp
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<User> Users => Set<User>();
public DbSet<Product> Products => Set<Product>();
}
```
### 3. 启动和使用(3 行代码)
```csharp
using Sharp.Data;
// 创建构建器并配置
var builder = new DataContextBuilder<AppDbContext>();
builder.UseSqlite("Data Source=app.db");
var db = builder.Build();
// 使用仓储
var userRepo = db.Repository<User>();
// 添加数据
await userRepo.AddAsync(new User
{
Name = "张三",
Email = "zhangsan@example.com"
});
await db.SaveChangesAsync(); // 如果使用 AuditableEntity,会自动记录 CreatedAt
// 查询数据
var users = await userRepo.GetAllAsync();
var user = await userRepo.FirstOrDefaultAsync(u => u.Email == "zhangsan@example.com");
// 分页查询(使用 Common 模块的 PagedResult)
var pagedUsers = await userRepo.GetPagedAsync(
page: 1,
pageSize: 20,
predicate: u => u.Name.Contains("张"),
orderBy: q => q.OrderByDescending(u => u.Id));
Console.WriteLine($"Total: {pagedUsers.TotalCount}, Pages: {pagedUsers.TotalPages}");
```
## 模块依赖
```
Sharp.Data
├── EF Core 8.0 (数据库访问)
└── Sharp.Common (复用基础功能)
├── PagedResult<T> (分页结果)
├── Result<T> (错误处理,可选)
└── 各种扩展方法
```
## 配置选项
### 使用不同数据库
```csharp
var builder = new DataContextBuilder<AppDbContext>();
// SQLite
builder.UseSqlite("Data Source=app.db");
// SQL Server
builder.UseSqlServer("Server=.;Database=MyApp;Trusted_Connection=True;");
// MySQL
builder.UseMySql("server=localhost;database=myapp;user=root;password=123456", "8.0.35");
// PostgreSQL
builder.UseNpgsql("Host=localhost;Database=myapp;Username=postgres;Password=123456");
// 内存数据库(用于测试)
builder.UseInMemoryDatabase("TestDb");
```
### 配置功能(所有功能都是可选的)
```csharp
var builder = new DataContextBuilder<AppDbContext>();
builder.UseSqlite("Data Source=app.db")
.UseAudit(true) // 启用审计(仅对实现 IAuditableEntity 的实体生效)
.UseSoftDelete(true) // 启用软删除(仅对实现 ISoftDeletable 的实体生效)
.UseAutoMigration(true) // 启动时自动迁移
.UseCurrentUser("user123") // 设置当前用户(用于审计)
.EnableDetailedErrors() // 启用详细错误信息
.EnableSensitiveDataLogging(); // 启用敏感数据日志(仅开发)
var db = builder.Build();
```
### 动态获取当前用户
```csharp
builder.UseCurrentUserProvider(() =>
{
// 从你的认证系统获取当前用户
return HttpContext.Current?.User?.Identity?.Name ?? "system";
});
```
## 实体基类(可选)
Data 模块提供了可选的实体基类,你**不是必须**使用它们:
### Entity<TKey> - 基础实体(可选)
```csharp
// Guid 主键(最常用)
public class Product : Entity { }
// Int 主键
public class Category : EntityInt { }
// Long 主键
public class Log : EntityLong { }
// 自定义主键类型
public class CustomEntity : Entity<string> { }
// 或者完全自定义
public class MyEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
```
### AuditableEntity<TKey> - 审计实体(可选)
如果继承此基类,会自动管理以下字段:
- `Id` - 主键
- `CreatedAt` - 创建时间
- `CreatedBy` - 创建人
- `UpdatedAt` - 更新时间
- `UpdatedBy` - 更新人
- `IsDeleted` - 是否删除
- `DeletedAt` - 删除时间
- `DeletedBy` - 删除人
```csharp
// 使用审计基类
public class User : AuditableEntity
{
public string Name { get; set; }
public string Email { get; set; }
}
// 或者自己实现审计接口
public class MyEntity : IAuditableEntity, ISoftDeletable
{
public Guid Id { get; set; }
public DateTime CreatedAt { get; set; }
public string? CreatedBy { get; set; }
// ... 实现其他接口属性
}
// 或者完全自定义(不使用审计)
public class SimpleEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
}
```
## 仓储方法
### 查询方法
```csharp
var repo = db.Repository<User>();
// 获取可查询对象
var query = repo.Query(trackChanges: false);
var activeUsers = await query.Where(u => u.Name.Contains("张")).ToListAsync();
// 根据主键获取
var user = await repo.GetByIdAsync(userId);
// 获取第一个符合条件的
var user = await repo.FirstOrDefaultAsync(u => u.Email == "test@example.com");
// 获取所有
var allUsers = await repo.GetAllAsync();
// 查找符合条件的
var users = await repo.FindAsync(u => u.Name.Contains("张"));
// 分页查询(返回 Common.ExpandFun.PagedResult<T>)
var pagedResult = await repo.GetPagedAsync(1, 20);
Console.WriteLine($"Total: {pagedResult.TotalCount}, Pages: {pagedResult.TotalPages}");
// 统计
var count = await repo.CountAsync(u => u.Name.Contains("张"));
var exists = await repo.AnyAsync(u => u.Email == "test@example.com");
```
### 修改方法
```csharp
// 添加
var user = new User { Name = "张三", Email = "zhang@example.com" };
await repo.AddAsync(user);
await db.SaveChangesAsync();
// 批量添加
var users = new List<User> { user1, user2, user3 };
await repo.AddRangeAsync(users);
await db.SaveChangesAsync();
// 更新
user.Name = "李四";
repo.Update(user);
await db.SaveChangesAsync();
// 删除(如果实体实现 ISoftDeletable,会软删除)
await repo.RemoveAsync(userId);
await db.SaveChangesAsync();
// 物理删除(对于未实现 ISoftDeletable 的实体)
repo.Remove(user);
await db.SaveChangesAsync();
```
## 查询扩展(复用 Common 模块)
```csharp
using Sharp.Data.Extensions;
using Common.ExpandFun; // PagedResult
// 分页扩展
var query = db.Context.Set<User>().Where(u => u.Name.Contains("张"));
var pagedResult = await query.ToPagedResultAsync(page: 1, pageSize: 20);
// 条件查询(来自 Common 模块的扩展)
var query = db.Context.Set<User>()
.WhereIf(!string.IsNullOrEmpty(searchTerm), u => u.Name.Contains(searchTerm));
// 动态排序
var query = db.Context.Set<User>()
.OrderByProperty("CreatedAt", descending: true);
```
## 最佳实践
### 1. 控制台应用
```csharp
using Sharp.Data;
var builder = new DataContextBuilder<AppDbContext>();
builder.UseSqlite("Data Source=app.db");
using var db = builder.Build();
// 使用 db 进行数据操作
var repo = db.Repository<User>();
await repo.AddAsync(new User { Name = "Test" });
await db.SaveChangesAsync();
// 自动释放资源
```
### 2. WPF 应用
```csharp
// App.xaml.cs
public partial class App : Application
{
public static IDataContext Database { get; private set; } = null!;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var builder = new DataContextBuilder<AppDbContext>();
builder.UseSqlite("Data Source=app.db")
.UseCurrentUserProvider(() => GetCurrentUser());
Database = builder.Build();
}
protected override void OnExit(ExitEventArgs e)
{
Database?.Dispose();
base.OnExit(e);
}
}
```
### 3. ASP.NET Core 应用
```csharp
// Program.cs
builder.Services.AddScoped<IDataContext>(sp =>
{
var dataBuilder = new DataContextBuilder<AppDbContext>();
dataBuilder.UseSqlServer(builder.Configuration.GetConnectionString("Default"))
.UseCurrentUserProvider(() =>
{
var httpContext = sp.GetService<IHttpContextAccessor>()?.HttpContext;
return httpContext?.User?.Identity?.Name ?? "anonymous";
});
return dataBuilder.Build();
});
builder.Services.AddHttpContextAccessor();
```
## 与其他 Sharp 模块集成
### 与 Sharp.Common 集成(已内置)
Data 模块已经引用了 Common 模块,可以直接使用:
- `PagedResult<T>` - 分页结果
- `Result<T>` - 错误处理(可选)
- 各种扩展方法
### 与 Sharp.Log 集成
```csharp
using Sharp.Log;
var loggerFactory = SharpLogDefaults.CreateLoggerFactory();
builder.ConfigureDbContext(options =>
{
options.UseLoggerFactory(loggerFactory);
});
```
## 高级功能
### 访问底层 DbContext
```csharp
var db = builder.Build();
// 执行原生 SQL
await db.Context.Database.ExecuteSqlRawAsync(
"DELETE FROM Logs WHERE CreatedAt < @p0",
DateTime.Now.AddDays(-30));
// 开始事务
using var transaction = await db.Context.Database.BeginTransactionAsync();
try
{
await db.SaveChangesAsync();
await transaction.CommitAsync();
}
catch
{
await transaction.RollbackAsync();
throw;
}
```
## 常见问题
### Q: 我必须使用 Entity/AuditableEntity 基类吗?
**不是!** 基类是**完全可选**的。你可以:
- 使用自己的实体定义
- 实现 `IAuditableEntity` 或 `ISoftDeletable` 接口
- 完全不使用审计和软删除功能
### Q: 如何使用自定义实体?
```csharp
// 完全自定义,不使用任何基类
public class MyEntity
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedAt { get; set; }
}
// 正常使用仓储
var repo = db.Repository<MyEntity>();
await repo.AddAsync(new MyEntity { Name = "Test" });
```
### Q: PagedResult 在哪里定义的?
`PagedResult<T>` 来自 `Sharp.Common` 模块(`Common.ExpandFun` 命名空间),Data 模块复用它以避免重复。
### Q: 如何禁用审计或软删除?
```csharp
builder.UseAudit(false) // 禁用审计
.UseSoftDelete(false); // 禁用软删除
```
## 性能建议
1. 查询时使用 `Query(trackChanges: false)` 提升性能
2. 批量操作使用 `AddRangeAsync`/`UpdateRange`
3. 生产环境关闭 `EnableSensitiveDataLogging`
4. 使用分页查询避免一次加载大量数据
## 许可证
MIT License