Entity Framework (EF) is a popular ORM framework for .
NET that allows
developers to interact with a database using .NET objects, eliminating the need
to write most of the SQL queries manually.
Object-Relational Mapping (ORM) is a programming technique used to convert
data between incompatible systems—in this case, between object-oriented
programming languages like C# and relational databases.
How Entity Framework Works for Database Integration
Entity Framework (EF) serves as a bridge between your application and the
database. It provides the following functionalities:
1. Mapping: EF maps your .NET classes to database tables and your class
properties to columns in those tables.
2. Queries: EF allows you to write LINQ (Language Integrated Query)
queries in C#, which EF translates into SQL queries that are executed
against the database.
3. Change Tracking: EF tracks changes made to the objects during runtime
and automatically generates the necessary SQL commands to update the
database.
4. Migrations: EF provides a way to handle changes to the database schema
over time through a process called migrations.
● Approaches with ORM :
When using an ORM, there are three main approaches to work with the database
schema:
1. Code-First Approach:
○ In this approach, you start by writing the classes (code) that
represent the data model. The ORM then generates the database
schema based on these classes.
○ Example: Entity Framework's Code-First approach.
2. Database-First Approach:
○ In this approach, you start with an existing database. The ORM
generates classes (entities) based on the existing database schema.
○ Example: Entity Framework's Database-First approach.
Note : Code-First is a specific approach under ORM where the database schema
is generated based on the classes you define in your code.
Example: ORM with Entity Framework in C#
Let's walk through a simple example to illustrate how EF works for database
integration:
1. Create a Model Class
● This class represents a table in the database.
public class Product //Entity class
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
2. Create a DbContext Class
● The DbContext class manages the database connection and acts as
a gateway to the database.
public class ApplicationDbContext : DbContext
public
ApplicationDbContext(DbContextOptions<ApplicationDbContext>
options)
: base(options)
public DbSet<Product> Products { get; set; }
3. Configure the Database Connection
● In your Program.cs, configure the DbContext to connect to your
database.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("D
efaultConnection")));
var app = builder.Build();
// Use your middlewares, controllers, etc.
app.MapControllers();
app.Run();
5. Define Connection Strings in appsettings.json
● Define the connection strings and database provider in appsettings.json:
{
"ConnectionStrings": {
"DefaultConnection": "YourConnectionStringForMSSQLOrPostgreSQL"
},
"DatabaseProvider": "SqlServer" // or "PostgreSQL"
}
6. Implement CRUD Operations
public class ProductService
private readonly ApplicationDbContext _context;
public ProductService(ApplicationDbContext context)
_context = context;
// Create a new product
public async Task CreateProduct(Product product)
_context.Products.Add(product);
await _context.SaveChangesAsync();
// Read products
public async Task<List<Product>> GetProducts()
return await _context.Products.ToListAsync();
}
// Update a product
public async Task UpdateProduct(Product product)
_context.Products.Update(product);
await _context.SaveChangesAsync();
// Delete a product
public async Task DeleteProduct(int id)
var product = await _context.Products.FindAsync(id);
if (product != null)
_context.Products.Remove(product);
await _context.SaveChangesAsync();
}
5. Apply Migrations
● Use EF migrations to create the database schema based on your
model classes.
dotnet ef migrations add InitialCreate //Add-Migration
dotnet ef database update //Update-Database
Summary:
● Model Class (Product): This represents a table in the database, where
each property corresponds to a column.
● DbContext (ApplicationDbContext): This is the primary class
responsible for interacting with the database. It maps the model classes to
database tables and handles database operations.
● CRUD Operations: You use the DbContext to create, read, update, and
delete records in the database.
● Migrations: Migrations allow you to evolve your database schema as your
application changes, without losing data.
Note : By using Entity Framework as an ORM, you can interact with the
database in an object-oriented way, making your code cleaner and reducing
the need to write raw SQL queries.
Database Configuration
1. Install Required Packages
● Use the following commands to add the necessary EF Core packages:
dotnet add package Microsoft.EntityFrameworkCore.SqlServer //Ms-sql server
dotnet add package Microsoft.EntityFrameworkCore.Npgsql //PostgreSql
2. Create the Entity Model
● Define your entity model class, which represents the database table.
public class Product //YourEntity
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedAt { get; set; }
}
3. Create the DbContext
● Define a DbContext.cs class to manage your database sessions within the Data
directory.
using dependencyInjection.Models;
using Microsoft.EntityFrameworkCore;
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options) { }
public DbSet<Product> Products { get; set; }
}
4. Configure the Database in Program.cs
● In ASP.NET Core 8.0, the Program.cs file combines the setup that was previously split
between Startup.cs and Program.cs.
Here's how to set up the database connection conditionally:
var builder = WebApplication.CreateBuilder(args);
// Load configuration from appsettings.json
var databaseProvider = builder.Configuration["DatabaseProvider"];
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
// Conditionally choose the database provider
if (databaseProvider == "SqlServer")
{
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
}
else if (databaseProvider == "PostgreSQL")
{
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(connectionString));
}
var app = builder.Build();
// Use your database and other middlewares
app.UseRouting();
app.MapControllers();
app.Run();
5. Define Connection Strings in appsettings.json
● Define the connection strings and database provider in appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"DefaultConnection":
"Server=LAPTOP-2C0VA32U\\MSSQLSERVER_ASUS;Database=ProductDb;Integrated
Security=True;MultipleActiveResultSets=True;TrustServerCertificate=True;"
},
"DatabaseProvider": "SqlServer" // or "PostgreSQL"
}
6. Implement CRUD Operations
● Create a repository class to handle CRUD operations:
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
namespace YourNamespace.Repositories
{
public class ProductRepository : IProductRepository
{
private readonly YourDbContext _context;
public ProductRepository(YourDbContext context)
{
_context = context;
}
// Get all products
public IEnumerable<Product> GetProducts()
{
return _context
// Get product by ID
public Product GetProductById(int productId)
{
return _context.Products.Find(productId);
}
// Add a new product
public void AddProduct(Product product)
{
_context.Products.Add(product);
Save();
}
// Update an existing product
public void UpdateProduct(Product product)
{
_context.Entry(product).State = EntityState.Modified;
Save();
}
// Delete a product by ID
public void DeleteProduct(int productId)
{
var product = _context.Products.Find(productId);
if (product != null)
{
_context.Products.Remove(product);
Save();
}
}
// Save changes to the database
public void Save()
{
_context.SaveChanges();
}
}
}
7. Apply Migrations
● Run the following commands to create and apply migrations:
dotnet ef migrations add InitialCreate //Add-Migration
dotnet ef database update //Update-Database
8. LINQ Query Syntax vs. Method Syntax (Lambda Expressions)
● Query Syntax (Plain LINQ Syntax):
○ This is the more SQL-like way of writing LINQ queries. It's often considered
the "plain" or "traditional" LINQ syntax because it resembles SQL query
structure.
○ Example:
var products = from p in context.Products
where p.Price > 100
orderby p.Name
select new { p.Name, p.Price };
Characteristics:
● It uses keywords like from, where, select, orderby, etc., similar to SQL.
● It can be more intuitive for those familiar with SQL.
● Suitable for simpler queries, but it may become cumbersome for more complex
operations.
Method Syntax (Lambda Expressions):
● This syntax involves calling LINQ extension methods directly on collections or
IQueryable objects. Lambda expressions are used to define the logic for these
methods.
● Example:
var products = context.Products
.Where(p => p.Price > 100)
.OrderBy(p => p.Name)
.Select(p => new { p.Name, p.Price })
.ToList();
Characteristics:
● It uses method calls like Where, OrderBy, Select, etc., with lambda expressions
to define operations.
● Often more concise and flexible, especially for complex queries.
● Allows for fluent chaining of methods.
- Example of Lambda Expressions with Entity Framework:
using (var context = new ApplicationDbContext())
{
var expensiveProducts = context.Products
.Where(p => p.Price > 100)
.OrderBy(p => p.Name)
.Select(p => new { p.Name, p.Price })
.ToList();
}
- using LINQ without lambda expressions would look like this:
using (var context = new ApplicationDbContext())
{
var expensiveProducts = from p in context.Products
where p.Price > 100
orderby p.Name
select new { p.Name, p.Price };
var resultList = expensiveProducts.ToList();
}