Accessing and manipulating data is a fundamental aspect of most applications. The .NET ecosystem provides a rich set of tools and frameworks to facilitate seamless data access. This section explores the primary approaches and technologies available for managing data in .NET.
ADO.NET
ADO.NET is a set of classes that expose data access services to the .NET Framework. It is the foundational technology for data access in .NET and provides a mechanism to connect to data sources, retrieve data, and manage data updates. Key components include:
SqlConnection
/OleDbConnection
/OdbcConnection
: For establishing connections to various database types.SqlCommand
/OleDbCommand
/OdbcCommand
: For executing SQL commands or stored procedures.SqlDataReader
/OleDbDataReader
/OdbcDataReader
: For reading query results in a forward-only, read-only manner.DataSet
andDataTable
: In-memory representation of data, useful for disconnected data scenarios.
Here's a simple example of fetching data using ADO.NET:
using System;
using System.Data;
using System.Data.SqlClient;
public class DataAccessExample
{
private const string ConnectionString = "Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;";
public static void GetCustomerData(int customerId)
{
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
string query = "SELECT CustomerName, Email FROM Customers WHERE CustomerID = @ID;";
SqlCommand command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("@ID", customerId);
try
{
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
Console.WriteLine($"Name: {reader["CustomerName"]}, Email: {reader["Email"]}");
}
}
else
{
Console.WriteLine("No customer found.");
}
reader.Close();
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}
}
Entity Framework Core
Entity Framework Core (EF Core) is a modern, cross-platform, open-source version of the popular Entity Framework data access technology. It is an Object-Relational Mapper (ORM) that enables .NET developers to work with databases using domain-specific objects, eliminating the need for most of the data-access code they typically need to write. EF Core supports LINQ queries, which allows you to query data using familiar C# or VB.NET syntax.
EF Core provides two main approaches for defining your model:
- Code First: You define your entities in C# code, and EF Core generates the database schema.
- Database First: EF Core inspects an existing database and generates the C# model classes.
Example using EF Core:
using Microsoft.EntityFrameworkCore;
public class ApplicationDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;");
}
}
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
public class EFCoreExample
{
public static void GetProducts(decimal minPrice)
{
using (var context = new ApplicationDbContext())
{
var expensiveProducts = context.Products
.Where(p => p.Price > minPrice)
.OrderBy(p => p.Name)
.ToList();
foreach (var product in expensiveProducts)
{
Console.WriteLine($"- {product.Name} (${product.Price})");
}
}
}
}
Data Providers
Both ADO.NET and EF Core rely on data providers to communicate with different types of data stores. .NET supports providers for a wide range of databases:
- SQL Server:
System.Data.SqlClient
(for .NET Framework) orMicrosoft.Data.SqlClient
(modern, recommended for .NET Core/5+). - SQLite:
Microsoft.Data.Sqlite
. - PostgreSQL:
Npgsql
. - MySQL:
MySql.Data
. - Oracle:
Oracle.ManagedDataAccess.Core
. - NoSQL Databases: Providers for MongoDB, Cosmos DB, Azure Table Storage, etc., are available through various NuGet packages.
When using EF Core, you install the appropriate EF Core provider package (e.g., Microsoft.EntityFrameworkCore.SqlServer
, Npgsql.EntityFrameworkCore.PostgreSQL
).
Transactions
Transactions are crucial for ensuring data consistency when performing multiple database operations. If one operation fails, the entire set of operations can be rolled back to a consistent state. ADO.NET provides
(or its equivalents for other providers) for managing transactions.SqlTransaction
EF Core also supports transactions, often implicitly through
operations, or explicitly using DbContext
.DbContext.Database.BeginTransaction()
using System;
using System.Data.SqlClient;
public class TransactionExample
{
private const string ConnectionString = "Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;";
public static void TransferFunds(int fromAccountId, int toAccountId, decimal amount)
{
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
connection.Open();
SqlTransaction transaction = null;
try
{
transaction = connection.BeginTransaction();
// Decrease balance from source account
string decreaseSql = "UPDATE Accounts SET Balance = Balance - @Amount WHERE AccountID = @FromAccount";
SqlCommand cmdDecrease = new SqlCommand(decreaseSql, connection, transaction);
cmdDecrease.Parameters.AddWithValue("@Amount", amount);
cmdDecrease.Parameters.AddWithValue("@FromAccount", fromAccountId);
cmdDecrease.ExecuteNonQuery();
// Increase balance to destination account
string increaseSql = "UPDATE Accounts SET Balance = Balance + @Amount WHERE AccountID = @ToAccount";
SqlCommand cmdIncrease = new SqlCommand(increaseSql, connection, transaction);
cmdIncrease.Parameters.AddWithValue("@Amount", amount);
cmdIncrease.Parameters.AddWithValue("@ToAccount", toAccountId);
cmdIncrease.ExecuteNonQuery();
// Commit the transaction
transaction.Commit();
Console.WriteLine("Funds transferred successfully.");
}
catch (Exception ex)
{
// Rollback the transaction if any error occurs
if (transaction != null)
{
transaction.Rollback();
}
Console.WriteLine($"Transaction failed: {ex.Message}");
}
}
}
}
Asynchronous Operations
Modern .NET applications leverage asynchronous programming to improve scalability and responsiveness, especially for I/O-bound operations like database access. ADO.NET and EF Core provide asynchronous methods (e.g.,
, ExecuteReaderAsync
) that should be used in asynchronous contexts.SaveChangesAsync
using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
public class AsyncDataAccessExample
{
public static async Task GetProductCountAsync(ApplicationDbContext context)
{
int count = await context.Products.CountAsync();
Console.WriteLine($"Total products: {count}");
}
}