Entity Framework Core (EF Core) 使用ado.net

Entity Framework Core 中使用 ADO.NET

在 Entity Framework Core (EF Core) 中,虽然提供了高级的 LINQ 查询和对象映射功能,但在某些特定场景下(如执行复杂 SQL、优化性能或调用存储过程),你可能需要直接使用 ADO.NET。EF Core 提供了多种方式与底层的 ADO.NET 进行交互,下面从几种常见场景详细介绍:

1. 通过 DbContext 获取 ADO.NET 连接

DbContext 提供了对底层数据库连接的访问,你可以直接使用这个连接执行 ADO.NET 命令。

1.1 获取数据库连接对象
using (var context = new ApplicationDbContext())
{
    // 获取 DbConnection 对象(已由 EF Core 管理)
    var connection = context.Database.GetDbConnection();
    
    try
    {
        // 确保连接已打开(EF Core 可能已自动打开)
        if (connection.State != System.Data.ConnectionState.Open)
        {
            await connection.OpenAsync();
        }
        
        // 创建 ADO.NET 命令
        using (var command = connection.CreateCommand())
        {
            command.CommandText = "SELECT COUNT(*) FROM Users WHERE Age > @Age";
            command.Parameters.AddWithValue("@Age", 18);
            
            // 执行命令
            var count = (int)await command.ExecuteScalarAsync();
            Console.WriteLine($"年龄大于 18 的用户数量: {count}");
        }
    }
    finally
    {
        // 无需手动关闭连接,EF Core 会管理连接生命周期
        // 若连接是由 EF Core 打开的,它会在适当的时候关闭
    }
}
1.2 使用事务集成

如果需要与 EF Core 的事务集成,可以使用 DbContext.Database.BeginTransaction()

using (var context = new ApplicationDbContext())
using (var transaction = await context.Database.BeginTransactionAsync())
{
    // 获取已在事务中的连接
    var connection = context.Database.GetDbConnection();
    
    using (var command = connection.CreateCommand())
    {
        command.Transaction = transaction.GetDbTransaction();
        command.CommandText = "UPDATE Users SET LastLogin = GETDATE() WHERE Id = @Id";
        command.Parameters.AddWithValue("@Id", 1);
        await command.ExecuteNonQueryAsync();
    }
    
    // EF Core 操作(与 ADO.NET 操作在同一事务中)
    var user = await context.Users.FindAsync(1);
    user.Status = "Active";
    await context.SaveChangesAsync();
    
    await transaction.CommitAsync();
}

2. 使用 FromSqlRaw/ExecuteSqlRaw 方法

EF Core 提供了 FromSqlRaw 和 ExecuteSqlRaw 方法,允许执行原始 SQL 语句,这些方法内部使用 ADO.NET 实现。

2.1 查询数据
var users = await context.Users
    .FromSqlRaw("SELECT * FROM Users WHERE Age > {0}", 18)
    .ToListAsync();
2.2 执行非查询命令
var rowsAffected = await context.Database.ExecuteSqlRawAsync(
    "UPDATE Users SET LastLogin = GETDATE() WHERE Id = {0}", 1);
2.3 调用存储过程
// 定义存储过程参数
var userId = new SqlParameter("@UserId", 1);
var outputParam = new SqlParameter("@Result", SqlDbType.Int) { Direction = ParameterDirection.Output };

// 执行存储过程
await context.Database.ExecuteSqlRawAsync(
    "EXEC sp_UserLogin @UserId, @Result OUTPUT", userId, outputParam);

// 获取输出参数值
var result = (int)outputParam.Value;

3. 使用 RelationalCommandBuilder 构建命令

对于更复杂的场景,可以使用 RelationalCommandBuilder 构建 ADO.NET 命令:

using (var context = new ApplicationDbContext())
{
    var commandBuilder = context.GetService<IRelationalCommandBuilderFactory>()
        .Create();
    
    commandBuilder
        .Append("SELECT * FROM Users WHERE Age > ")
        .AppendParameter("age", 18);
    
    var command = commandBuilder.Build();
    
    using (var connection = context.Database.GetDbConnection())
    {
        await connection.OpenAsync();
        
        using (var dbCommand = command.CreateDbCommand())
        {
            dbCommand.Connection = connection;
            using (var reader = await dbCommand.ExecuteReaderAsync())
            {
                while (await reader.ReadAsync())
                {
                    var id = reader.GetInt32(0);
                    var name = reader.GetString(1);
                    Console.WriteLine($"User: {id}, {name}");
                }
            }
        }
    }
}

4. 性能考虑

直接使用 ADO.NET 通常用于性能优化,但需要注意:

4.1 避免 N+1 查询问题

对于复杂查询,直接使用 ADO.NET 可以避免 EF Core 的 N+1 查询问题:

// EF Core 可能产生 N+1 查询
var orders = await context.Orders
    .Include(o => o.Customer)
    .ToListAsync();

// 使用 ADO.NET 执行单个查询
var sql = @"
    SELECT o.Id, o.OrderDate, c.Id, c.Name 
    FROM Orders o
    JOIN Customers c ON o.CustomerId = c.Id";

using (var command = connection.CreateCommand())
{
    command.CommandText = sql;
    // 处理结果集...
}
4.2 批量操作

对于大批量数据操作,ADO.NET 的 SqlBulkCopy 比 EF Core 更高效:

using (var context = new ApplicationDbContext())
{
    var connection = (SqlConnection)context.Database.GetDbConnection();
    await connection.OpenAsync();
    
    using (var bulkCopy = new SqlBulkCopy(connection))
    {
        bulkCopy.DestinationTableName = "Users";
        await bulkCopy.WriteToServerAsync(dataTable); // dataTable 包含要插入的数据
    }
}

5. 注意事项

  1. 连接管理:EF Core 管理连接生命周期,通常不需要手动打开 / 关闭连接。
  2. 参数化查询:始终使用参数化查询(如 {0} 或 @Parameter)避免 SQL 注入。
  3. 事务集成:确保 ADO.NET 命令与 EF Core 操作在同一事务中(如果需要原子性)。
  4. 映射复杂性:手动处理结果集映射比 EF Core 的自动映射更复杂。
  5. 跨数据库兼容性:直接编写的 SQL 可能不支持多种数据库提供者。

总结

在 EF Core 中使用 ADO.NET 主要通过获取底层数据库连接或使用原始 SQL 方法实现。这种方式适合执行复杂 SQL、优化性能或调用存储过程,但需要权衡手动管理的复杂性和潜在的兼容性问题。在大多数情况下,优先使用 EF Core 的高级 API,仅在必要时才使用 ADO.NET 进行底层操作。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王柏龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值