FivePD API

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.

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();
}