In modern web applications, working with data is crucial, and Entity Framework Core (EF Core) provides an efficient way to interact with databases using an Object-Relational Mapping (ORM) approach. EF Core offers two primary ways to handle data in an application: the Connected and Disconnected scenarios. Both scenarios are critical in various use cases and have different approaches to how data is retrieved, tracked, and saved to the database. This article explores both these concepts with practical solutions in a .NET Core MVC application.
What is a Connected Scenario?
In a Connected scenario, the DbContext is directly connected to the entity instances and actively tracks changes made to the data. This is the default behavior of EF Core when entities are retrieved using a context and modified within the scope of the context.
Key Characteristics of a Connected Scenario
- Change Tracking: EF Core automatically tracks changes made to the entities. When SaveChanges() is called, it updates the database with those changes.
- Short-lived Context: The DbContext instance is created, used, and disposed of within a limited scope, often tied to a single HTTP request in a web application.
- Automatic State Management: EF Core keeps track of the state of entities, such as Added, Modified, Deleted, and Unchanged.
Practical Example
Let’s create a simple CRUD operation in a Connected scenario for managing a list of users.
Create the Model
namespace EFCoreConnectedDisconnectedDemo.Model
{
public class User
{
public int Id { get; set; }
public string? Name { get; set; }
public string? Email { get; set; }
}
}
Set Up DbContext
using EFCoreConnectedDisconnectedDemo.Model;
using Microsoft.EntityFrameworkCore;
namespace EFCoreConnectedDisconnectedDemo.ApplicationContext
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
public DbSet<User> Users { get; set; }
}
}
Create the controller
using EFCoreConnectedDisconnectedDemo.ApplicationContext;
using EFCoreConnectedDisconnectedDemo.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace EFCoreConnectedDisconnectedDemo.Controllers
{
public class UserController : Controller
{
private readonly ApplicationDbContext _context;
public UserController(ApplicationDbContext context)
{
_context = context;
}
// GET: User
public IActionResult Index()
{
var users = _context.Users.ToList();
return View(users);
}
// GET: User/Create
public IActionResult Create()
{
return View();
}
// POST: User/Create
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create([Bind("Id, Name, Email")] User user)
{
if (ModelState.IsValid)
{
_context.Add(user);
_context.SaveChanges(); // Save the changes in the connected scenario
return RedirectToAction(nameof(Index));
}
return View(user);
}
// GET: User/Edit/5
public IActionResult Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var user = _context.Users.Find(id);
if (user == null)
{
return NotFound();
}
return View(user);
}
// POST: User/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(int id, [Bind("Id, Name, Email")] User user)
{
if (id != user.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(user);
_context.SaveChanges(); // EF Core automatically tracks changes and updates the database
}
catch (DbUpdateConcurrencyException)
{
if (!_context.Users.Any(e => e.Id == user.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(user);
}
// GET: User/Delete/5
public IActionResult Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var user = _context.Users
.FirstOrDefault(m => m.Id == id);
if (user == null)
{
return NotFound();
}
return View(user);
}
// POST: User/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(int id)
{
var user = _context.Users.Find(id);
_context.Users.Remove(user);
_context.SaveChanges(); // EF Core will automatically track the deletion
return RedirectToAction(nameof(Index));
}
}
}
Join the conversation! Your thoughts help the community grow.