Database access
The DatabaseContext provides direct access to the underlying Entity Framework Core database for advanced scenarios where existing API methods don't meet your needs.
This documentation covers the recommended patterns for safe database access in FivePD addons.
If you haven't used Entity Framework previously we recommend checking out the official documentation before diving into it.
Note that due to some FiveM limitations we can only use Entity Framework Core version 3.1.26, so make sure you're reading the correct documentation.
Recommended Usage Pattern
Use the IDatabaseContextFactory to create scoped database contexts. This ensures proper disposal and prevents memory leaks.
Basic Usage
using CitizenFX.Core;
using FivePD.Server.API;
using FivePD.Server.Interfaces;
namespace MyAwesomeAddon;
public class MyAwesomeExtension : IExtension
{
private readonly IDatabaseContextFactory _dbContextFactory;
public MyAwesomeExtension(IDatabaseContextFactory dbContextFactory)
{
this._dbContextFactory = dbContextFactory;
}
public Task OnStarted()
{
using var databaseContext = this._dbContextFactory.CreateScope().Context;
var users = databaseContext.Users.ToList();
return Task.FromResult(0);
}
public Task OnStopped()
{
return Task.FromResult(0);
}
}Context Management Best Practices
Creating Contexts
- Each method should create its own context: using
using var databaseContext = this._dbContextFactory.CreateScope().Context; - Never store contexts as class fields: they should be short-lived and disposed properly
- Contexts are not thread-safe: each thread/operation needs its own context
Passing Contexts Between Methods
If you need to perform multiple database operations in sequence, you have two options:
Option 1: Pass the existing context
public void UpdateUserAndDepartment(int userId, int departmentId)
{
using var dbContext = this._dbContextFactory.CreateScope().Context;
var user = UpdateUser(dbContext, userId);
var department = UpdateDepartment(dbContext, departmentId);
dbContext.SaveChanges();
}
private User UpdateUser(DatabaseContext dbContext, int userId)
{
var user = dbContext.Users.Find(userId);
user.LastModified = DateTime.UtcNow;
return user;
}Option 2: Create new context and attach entities for change tracking
public void UpdateUserAndDepartment(int userId, int departmentId)
{
User user;
Department department;
using var dbContext = this._dbContextFactory.CreateScope().Context);
user = dbContext.Users.Find(userId);
department = dbContext.Departments.Find(departmentId);
UpdateUserAndDepartmentInAnotherClass(user, department);
}
private void UpdateUserAndDepartmentInAnotherClass(User user, Department department)
{
using var dbContext = this._dbContextFactory.CreateScope().Context);
dbContext.Users.Attach(user);
dbContext.Departments.Attach(department);
user.LastModified = DateTime.UtcNow;
department.UpdatedBy = "MyAwesomeExtension";
dbContext.SaveChanges();
}