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 进行底层操作。

相关推荐
····懂···1 小时前
开源数据库PostgreSQL专家技术
数据库·postgresql·开源
Asu52021 小时前
思途SQL学习 0729
数据库·sql·学习
北亚数据恢复2 小时前
服务器数据恢复—RAID上层部署的oracle数据库数据恢复案例
数据库·oracle·服务器数据恢复·北亚数据恢复
不辉放弃3 小时前
kafka的消息存储机制和查询机制
数据库·kafka·pyspark·大数据开发
ZZH1120KQ4 小时前
ORACLE的用户维护与权限操作
数据库·oracle
妮妮喔妮4 小时前
图片上传 el+node后端+数据库
javascript·数据库·vue.js
仰望星空的凡人10 小时前
【JS逆向基础】数据库之MongoDB
javascript·数据库·python·mongodb
duration~11 小时前
PostgreSQL并发控制
数据库·postgresql
给力学长12 小时前
自习室预约小程序的设计与实现
java·数据库·vue.js·elementui·小程序·uni-app·node.js
迷茫运维路13 小时前
MySQL5.7主从延迟高排查优化思路
数据库·主从延时高