Back to .md Directory

Question

Answers how to model a single users table with role-based vehicle relationships in EF Core, comparing three design options.

May 2, 2026
0 downloads
1 views
ai
View source

What this file does

Answers how to model a single users table with role-based vehicle relationships in EF Core, comparing three design options.

When to use it

  • Designing a database with a single users table for multiple roles
  • Needing EF Core navigation properties that depend on user role
  • Deciding between conditional loading, backing fields, or table splitting
  • Enforcing that only drivers have a vehicles relationship

Assumes this stack

C#EF CoreSQL

Question

I have a concern like this: in the database, there will be no distinct tables for passengers, drivers or managers, but only a users table. therefore there should only be User entity (EF Core) to map to the table. however, the users table has one-to-many relationship with vehicles, and this should only apply to users that have role driver (Role is an entity, representing the roles table). How should I handle this?


Answer

This is a common issue in EF Core when using a single "Users" table for multiple roles while enforcing role-based constraints . Since only drivers should have a vehicles relationship, you have a few design options:


Option 1: Use Navigation Property with Conditional Loading

You keep a single User entity , but filter vehicle access based on role .

Implementation

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Role Role { get; set; }  // Navigation property to Role
    public int RoleId { get; set; } // Foreign Key

    // Navigation property: Only relevant for Drivers
    public List<Vehicle>? Vehicles { get; set; }
}
public class Vehicle
{
    public int Id { get; set; }
    public string LicensePlate { get; set; }
    public int UserId { get; set; } // FK to User
    public User User { get; set; }  // Navigation property
}

Enforcing the Role Restriction

You filter access to vehicles in queries (prevent non-drivers from having vehicles):

var driversWithVehicles = dbContext.Users
    .Where(u => u.Role.Name == "Driver")
    .Include(u => u.Vehicles)
    .ToList();

📌 Pros : Keeps database simple, avoids unnecessary table inheritance.

📌 Cons : Need to manually enforce role-based constraints in logic.


Option 2: Use Backing Fields with Explicit Role Checks

Instead of exposing Vehicles to all users, use a private backing field to ensure only drivers have access.

Implementation

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Role Role { get; set; }
    public int RoleId { get; set; }

    // Private field (EF Core still maps this correctly)
    private List<Vehicle>? _vehicles;

    // Public property ensures only Drivers can access
    public IReadOnlyList<Vehicle>? Vehicles
        => Role?.Name == "Driver" ? _vehicles : null;
}

📌 Pros : Prevents incorrect usage at the code level.

📌 Cons : Requires manual enforcement at object level (EF Core does not enforce this automatically).


Option 3: Table Splitting (Single Table with Different Mappings)

EF Core table splitting allows mapping a subset of properties only when a condition is met .

Implementation

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Role Role { get; set; }
}

public class Driver
{
    public int Id { get; set; } // Same as User Id
    public List<Vehicle> Vehicles { get; set; }
}

EF Core Fluent API Mapping

modelBuilder.Entity<User>()
    .ToTable("Users");

modelBuilder.Entity<Driver>()
    .ToTable("Users") // Same table
    .HasOne<Role>()
    .WithMany()
    .HasForeignKey(u => u.Id)
    .HasPrincipalKey(u => u.Id);

📌 Pros : EF Core ensures only drivers have vehicles automatically.

📌 Cons : More complex EF Core configuration.


Which Approach is Best?

ApproachSimplicityEnforces Role ConstraintWorks Well with EF Core
1: Conditional Loading✅ Simple❌ Manual enforcement✅ Good for performance
2: Backing Fields✅ Simple✅ Enforces constraint✅ Works well
3: Table Splitting❌ Complex✅ Automatic enforcement✅ EF Core manages well

📌 Recommendation

  • If you want a simple solution → Use Option 1 (Conditional Loading)
  • If you want stricter role constraints → Use Option 2 (Backing Fields)
  • If EF Core should enforce the structure automatically → Use Option 3 (Table Splitting)

Do you want help implementing one of these fully in Fluent API ? 🚀


References

What's inside

3 design options with code examples, a comparison table, and a recommendation section.

Change this for your project

  • Replace Role.Name == "Driver" with your actual role name
  • Replace dbContext.Users with your own DbContext instance name

Where it goes

Keep it in your repository where the agent or team that needs it will read it.

Worth borrowing

  • Using a private backing field with a role-checked public property to enforce constraints at the code level
  • Table splitting to map two entities to the same table for automatic role-based mapping

Related Documents