Entity Framework Core (EF Core) 中Database

发布于:2025-07-29 ⋅ 阅读:(16) ⋅ 点赞:(0)

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


网站公告

今日签到

点亮在社区的每一天
去签到