Entity Framework Core (EF Core) 中Database

在 Entity Framework Core (EF Core) 中,Database属性的类型是DatabaseFacadeDatabaseFacade 是一个关键的门面类,提供对数据库相关操作的统一访问接口。它封装了与底层数据库交互的核心功能,包括连接管理、事务处理、执行原始 SQL 以及数据库迁移等操作。下面从功能、用法、常见场景和最佳实践几个方面详细解析:

1. 核心功能

DatabaseFacade 提供以下主要功能:

复制代码
// 获取底层 DbConnection
var connection = context.Database.GetDbConnection();

// 检查连接状态
if (context.Database.GetDbConnection().State != ConnectionState.Open)
{
    await context.Database.OpenConnectionAsync();
}

// 执行连接相关操作
var databaseName = context.Database.GetDbConnection().Database;
1.2 事务处理
复制代码
// 开始事务
await using var transaction = await context.Database.BeginTransactionAsync();

try
{
    // 执行数据操作
    context.Users.Add(new User { Name = "John" });
    await context.SaveChangesAsync();

    // 提交事务
    await transaction.CommitAsync();
}
catch (Exception)
{
    // 回滚事务
    await transaction.RollbackAsync();
}
1.3 执行原始 SQL
复制代码
// 执行查询
var users = await context.Users
    .FromSqlRaw("SELECT * FROM Users WHERE Age > {0}", 18)
    .ToListAsync();

// 执行非查询命令
var rowsAffected = await context.Database.ExecuteSqlRawAsync(
    "UPDATE Users SET LastLogin = GETDATE() WHERE Id = {0}", 1);
1.4 数据库迁移
复制代码
// 应用所有待迁移的更改
await context.Database.MigrateAsync();

// 检查是否需要迁移
bool pendingMigrations = (await context.Database.GetPendingMigrationsAsync()).Any();

// 创建数据库(如果不存在)
await context.Database.EnsureCreatedAsync();
1.5 数据库状态检查
复制代码
// 检查数据库是否存在
bool exists = await context.Database.EnsureExistsAsync();

// 检查数据库架构是否与模型匹配
bool isCompatible = await context.Database.CanConnectAsync();

2. 获取 DatabaseFacade 实例

DbContext 中,可以通过 Database 属性访问 DatabaseFacade

复制代码
public class ApplicationDbContext : DbContext
{
    public DbSet<User> Users { get; set; }

    // 通过基类的 Database 属性访问 DatabaseFacade
    public void SomeMethod()
    {
        // 执行数据库操作
        this.Database.ExecuteSqlRaw("UPDATE Users SET ...");
    }
}

3. 常见应用场景

3.1 复杂查询优化

对于 EF Core 查询性能不佳的场景,使用原始 SQL:

复制代码
var results = await context.Set<ComplexResult>()
    .FromSqlRaw("EXEC sp_GetComplexData @Param1, @Param2", param1, param2)
    .ToListAsync();
3.2 批量操作

执行批量更新或删除:

复制代码
await context.Database.ExecuteSqlRawAsync(
    "DELETE FROM Orders WHERE OrderDate < {0}", DateTime.Now.AddYears(-1));
3.3 数据库初始化与迁移

在应用启动时确保数据库和架构存在:

复制代码
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    using (var scope = app.ApplicationServices.CreateScope())
    {
        var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        context.Database.Migrate(); // 应用所有迁移
    }
    
    // 其他配置...
}
3.4 分布式事务

结合 ADO.NET 使用分布式事务:

复制代码
await using var transaction = await context.Database.BeginTransactionAsync();

try
{
    // EF Core 操作
    context.Users.Add(new User { Name = "Alice" });
    await context.SaveChangesAsync();

    // ADO.NET 操作(使用相同连接)
    var connection = context.Database.GetDbConnection();
    using (var command = connection.CreateCommand())
    {
        command.Transaction = transaction.GetDbTransaction();
        command.CommandText = "UPDATE Log SET Status = 'Processed' WHERE Id = 1";
        await command.ExecuteNonQueryAsync();
    }

    await transaction.CommitAsync();
}
catch (Exception)
{
    await transaction.RollbackAsync();
    throw;
}

4. 高级用法

4.1 控制连接超时
复制代码
context.Database.SetCommandTimeout(TimeSpan.FromMinutes(2)); // 设置 2 分钟超时
4.2 拦截数据库操作

通过自定义拦截器记录 SQL 执行时间:

复制代码
public class SqlLoggingInterceptor : DbCommandInterceptor
{
    private readonly ILogger _logger;

    public SqlLoggingInterceptor(ILogger<SqlLoggingInterceptor> logger)
    {
        _logger = logger;
    }

    public override InterceptionResult<DbDataReader> ReaderExecuting(
        DbCommand command, 
        CommandEventData eventData, 
        InterceptionResult<DbDataReader> result)
    {
        _logger.LogInformation("Executing SQL: {Sql}", command.CommandText);
        return base.ReaderExecuting(command, eventData, result);
    }
}

// 在 DbContext 中注册拦截器
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.AddInterceptors(new SqlLoggingInterceptor(_logger));
}
4.3 多数据库操作

在多个 DbContext 之间共享事务:

复制代码
await using var transaction = await context1.Database.BeginTransactionAsync();

try
{
    // 操作 context1
    context1.Users.Add(new User { Name = "Bob" });
    await context1.SaveChangesAsync();

    // 操作 context2(使用相同事务)
    context2.Orders.Add(new Order { UserId = 1 });
    await context2.SaveChangesAsync();

    await transaction.CommitAsync();
}
catch (Exception)
{
    await transaction.RollbackAsync();
    throw;
}

5. 注意事项

5.1 原始 SQL 的安全性

始终使用参数化查询,避免 SQL 注入:

复制代码
// 安全写法
await context.Database.ExecuteSqlRawAsync(
    "UPDATE Users SET Name = {0} WHERE Id = {1}", newName, id);

// 不安全写法(避免)
await context.Database.ExecuteSqlRawAsync(
    $"UPDATE Users SET Name = '{newName}' WHERE Id = {id}");
5.2 跨数据库兼容性

直接编写的 SQL 可能不支持多种数据库提供者(如 SQL Server 和 PostgreSQL 的语法差异)。

5.3 事务边界

确保事务的生命周期正确管理,避免长时间持有事务导致锁争用。

5.4 性能考虑

频繁调用 DatabaseFacade 方法可能影响性能,优先使用 EF Core 的 LINQ 查询。

总结

DatabaseFacade 是 EF Core 中连接应用程序和底层数据库的桥梁,提供了丰富的数据库操作功能。它在需要执行原始 SQL、管理事务或进行数据库迁移时特别有用。但在使用时应权衡其灵活性与潜在风险,遵循最佳实践以确保代码的安全性和可维护性。在大多数情况下,优先使用 EF Core 的高级 API,仅在必要时才通过 DatabaseFacade 进行底层操作。

相关推荐
野犬寒鸦10 小时前
从零起步学习MySQL || 第十章:深入了解B+树及B+树的性能优势(结合底层数据结构与数据库设计深度解析)
java·数据库·后端·mysql·1024程序员节
GZ_TOGOGO10 小时前
Oracle OCP考试报名常见问题详解
数据库·oracle·ocp认证
睡不醒的猪儿10 小时前
nginx日志同步阿里云datahub后写入数据库
数据库·nginx·阿里云
xie_zhr11 小时前
【PB案例学习笔记】-46在数据窗口中编辑数据
数据库·his·1024程序员节·干货分享·pb·powerbuilder
小小的木头人11 小时前
Redis 集群安装指南
数据库·redis
星空的资源小屋11 小时前
Antares SQL,一款跨平台开源 SQL 客户端
数据库·人工智能·pdf·开源·电脑·excel·1024程序员节
2301_8002561111 小时前
地理空间数据库作业笔记——查询最偏僻的城市
数据库·笔记·sql·postgresql·1024程序员节
卓码软件测评12 小时前
软件可用性测试历史概念✅软件可用性测试的国际标准✅软件可用性测试方法
数据库·单元测试·可用性测试·软件需求
R.lin12 小时前
OSS服务模块-基于数据库配置的Java OSS服务解决方案,支持MinIO、七牛云、阿里云和腾讯云
java·数据库·后端·mysql
橄榄熊12 小时前
使用VScode 插件,连接MySQL,可视化操作数据库
数据库·mysql