116 lines
4.3 KiB
C#
Raw Normal View History

2026-05-21 15:52:36 +08:00
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
2026-05-22 14:29:22 +08:00
namespace FileShare_EFCore.Database
2026-05-21 15:52:36 +08:00
{
/// <summary>
/// 应用数据库上下文基类 —— 自动根据 DatabaseConfiguration 选择数据库提供程序。
/// 所有业务 DbContext 继承此类即可获得多数据库支持。
/// </summary>
public abstract class AppDbContext(DatabaseConfiguration dbConfig) : DbContext
{
/// <summary>
/// 数据库配置。
/// </summary>
private readonly DatabaseConfiguration _dbConfig = dbConfig;
/// <summary>
/// 配置数据库提供程序和连接选项。
/// </summary>
/// <param name="optionsBuilder">选项构建器。</param>
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (optionsBuilder.IsConfigured) return;
ConfigureProvider(optionsBuilder, _dbConfig);
if (_dbConfig.EnableDetailedLog)
{
optionsBuilder.LogTo(Console.WriteLine, Microsoft.Extensions.Logging.LogLevel.Information);
}
// 启用详细的 EF Core 错误信息
optionsBuilder.EnableDetailedErrors();
optionsBuilder.EnableSensitiveDataLogging(_dbConfig.EnableDetailedLog);
}
/// <summary>
/// 根据配置选择数据库提供程序。
/// 使用注册模式,由宿主项目注册具体的提供程序实现。
/// </summary>
public static void ConfigureProvider(DbContextOptionsBuilder optionsBuilder, DatabaseConfiguration config)
{
if (DatabaseProviderRegistry.TryGet(config.Provider, out var configurator))
{
configurator(optionsBuilder, config.ConnectionString, config.Timeout);
}
else
{
throw new NotSupportedException(
$"数据库提供程序 {config.Provider} 未注册。" +
$"请在宿主项目中安装对应的 EF Core NuGet 包并调用 DatabaseProviderRegistry.Register()。");
}
optionsBuilder.EnableDetailedErrors();
optionsBuilder.EnableSensitiveDataLogging(config.EnableDetailedLog);
if (config.EnableDetailedLog)
{
optionsBuilder.LogTo(Console.WriteLine, Microsoft.Extensions.Logging.LogLevel.Information);
}
}
/// <summary>
/// 保存时自动设置时间戳。
/// </summary>
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
SetTimestamps();
return base.SaveChanges(acceptAllChangesOnSuccess);
}
/// <summary>
/// 异步保存更改,自动设置时间戳。
/// </summary>
/// <param name="acceptAllChangesOnSuccess">是否在成功时接受所有更改。</param>
/// <param name="cancellationToken">取消令牌。</param>
/// <returns>受影响的行数。</returns>
public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)
{
SetTimestamps();
return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
/// <summary>
/// 自动设置新增或修改实体的 CreatedAt 和 UpdatedAt 时间戳。
/// </summary>
private void SetTimestamps()
{
var entries = ChangeTracker.Entries()
.Where(e => e.State == EntityState.Added || e.State == EntityState.Modified);
foreach (var entry in entries)
{
var entity = entry.Entity;
// 使用反射设置 CreatedAt / UpdatedAt如果存在
var createdAtProp = entity.GetType().GetProperty("CreatedAt");
var updatedAtProp = entity.GetType().GetProperty("UpdatedAt");
if (entry.State == EntityState.Added && createdAtProp != null)
{
createdAtProp.SetValue(entity, DateTime.UtcNow);
}
if (updatedAtProp != null)
{
updatedAtProp.SetValue(entity, DateTime.UtcNow);
}
}
}
}
}