A:增加数据库配置和使用
This commit is contained in:
1 parent
53d1dd2dbf
commit
f7660c49e8
86 files changed
+7401
-271
No files matched your search
@@ -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
|
||||
Reference in new issue
Block a user