DAL (Data Access Layer)
این کلاس یک Generic/Reusable Data Access class است که: 1. مسئولیت باز/بستن Connection را از دوش کد بالادستی برمیدارد 2. از SQL Injection با `SqlParameter` جلوگیری میکند 3. هم Raw SQL و هم Stored Procedure را با `CommandType` پشتیبانی میکند 4. معمولاً به عنوان یک Singleton/Scoped Service در DI Container ثبت میشود و در `Repository`های دیگر (مثل `UserRepository`) تزریق و استفاده میشود.
using System.Data;
using Microsoft.Data.SqlClient;
namespace SqlForDevelopers.Data;
public class SqlDataContext
{
private readonly IConfiguration _config;
public SqlDataContext(IConfiguration config)
{
_config = config;
}
private SqlConnection CreateConnection()
=> new SqlConnection(_config.GetConnectionString("DefaultConnection"));
// DELETE , INSERT, UPDATE
public async Task<int> ExecuteNonQueryAsync(string cmdText, CommandType type, params SqlParameter[] parameters)
{
await using var connection = CreateConnection();
await using var cmd = new SqlCommand(cmdText, connection) { CommandType = type }; // it determined whether it is Raw Sql or Stored Procedure
if (parameters?.Length>0) cmd.Parameters.AddRange(parameters);
await connection.OpenAsync();
return await cmd.ExecuteNonQueryAsync();
}
// Return a field of table (1 row , 1 column)
public async Task<object> ExecuteScalarAsync(string cmdText, CommandType type, params SqlParameter[] parameters)
{
await using var connection = CreateConnection();
await using var cmd = new SqlCommand(cmdText, connection) { CommandType = type }; // it determined whether it is Raw Sql or Stored Procedure
if (parameters?.Length > 0) cmd.Parameters.AddRange(parameters);
await connection.OpenAsync();
return await cmd.ExecuteScalarAsync(); // SELECT
}
// Return several row/column
public async Task<List<T>> ExecuteReaderAsync<T>(string cmdText, CommandType type,
Func<SqlDataReader, T> map, params SqlParameter[] parameters)
{
var list = new List<T>();
await using var connection = CreateConnection();
await using var cmd = new SqlCommand(cmdText, connection) { CommandType = type };
if (parameters?.Length > 0) cmd.Parameters.AddRange(parameters);
await connection.OpenAsync();
await using var reader= await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
list.Add(map(reader));
}
return list;
}
}
ExecuteNonQueryAsync → INSERT / UPDATE / DELETE → تعداد ردیف تحت تأثیر (int)
ExecuteScalarAsync → SELECT با یک مقدار تکی → یک object
ExecuteReaderAsync<T> → SELECT با چند ردیف → List<T>
کد مکمل یا نمونه استفاده همراه (Companion / Setup Code)
مشاهده کد
Microsoft.Data.SqlClient Package
پیشنیازها و کدهای پایه:
1 مورد
مراحل بعد و کدهای تکمیلی:
1 مورد