Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/marchena96/Paradigma-lab1/llms.txt

Use this file to discover all available pages before exploring further.

LibraryService API persists data through two EF Core entities — Library and Book — both defined in LibraryContext.cs and mapped to PostgreSQL tables (Libraries and Books) on Supabase. There is no Fluent API configuration; column types and constraints come entirely from the InitialCreate migration.

Library entity

C# class

public class Library
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }

    public string Location { get; set; }
}

Table schema — Libraries

ColumnTypeConstraints
IdintegerPK, Identity (auto-increment)
NametextNOT NULL
LocationtextNOT NULL

Example JSON

{
  "id": 5,
  "name": "Library name",
  "location": "2838 Violet Ct, Columbus, IN 47201, USA"
}

Book entity

C# class

public class Book
{
    [Key]
    public int Id { get; set; }

    public string Name { get; set; }

    public string Category { get; set; }

    public int LibraryId { get; set; }
    public virtual Library Library { get; set; }
}

Table schema — Books

ColumnTypeConstraints
IdintegerPK, Identity (auto-increment)
NametextNOT NULL
CategorytextNOT NULL
LibraryIdintegerFK → Libraries.Id, ON DELETE CASCADE
An index IX_Books_LibraryId is created on LibraryId to speed up the per-library book queries issued by BooksService.

Example JSON

{
  "id": 3,
  "name": "The Norton Anthology of English Literature",
  "category": "Anthology",
  "libraryId": 5
}

Relationship

One Library has many Book records. The FK column LibraryId on the Books table references Libraries.Id with ON DELETE CASCADE, meaning that deleting a library automatically and atomically deletes all of its books at the PostgreSQL level — no application-level cleanup is required. This relationship is declared in the InitialCreate migration:
table.ForeignKey(
    name: "FK_Books_Libraries_LibraryId",
    column: x => x.LibraryId,
    principalTable: "Libraries",
    principalColumn: "Id",
    onDelete: ReferentialAction.Cascade);

LibraryContext

LibraryContext is the single EF Core DbContext for the application. It exposes the two entity sets and accepts its options through constructor injection:
public class LibraryContext : DbContext
{
    public LibraryContext(DbContextOptions<LibraryContext> options)
        : base(options)
    { }

    public DbSet<Library> Libraries { get; set; }
    public DbSet<Book> Books { get; set; }
}
LibraryContext is registered in Startup.ConfigureServices as a DbContext pool (not a plain scoped service) to minimise the overhead of context creation under load:
services.AddDbContextPool<LibraryContext>(options =>
    options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"), npgsqlOptions =>
    {
        npgsqlOptions.EnableRetryOnFailure(
            maxRetryCount: 1,
            maxRetryDelay: TimeSpan.FromSeconds(5),
            errorCodesToAdd: null);
    }),
    poolSize: 20);
Key configuration points:
  • Pool size 20 — up to 20 context instances are kept alive and reused across requests.
  • Npgsql retry-on-failure — transient connection errors trigger up to 1 automatic retry with a 5-second maximum delay.

Migrations

EF Core migrations provide a versioned history of every schema change. The sole migration in this project is 20260528004745_InitialCreate, which creates both tables and the cascade FK in a single Up() operation. Migrations are applied automatically at startup via db.Database.Migrate() inside Startup.Configure:
using (var scope = app.ApplicationServices.CreateScope())
{
    var db = scope.ServiceProvider.GetRequiredService<LibraryContext>();

    // Integration tests substitute LibraryContext with an SQLite in-memory database
    // created via EnsureCreated — Migrate() would conflict with that schema.
    // Auto-migration only runs for the real provider (Npgsql/PostgreSQL) when there
    // are pending migrations.
    var isSqliteTestDb = db.Database.ProviderName?.Contains("Sqlite", StringComparison.OrdinalIgnoreCase) == true;
    if (!isSqliteTestDb && db.Database.GetPendingMigrations().Any())
    {
        db.Database.Migrate();
    }
}
The guard skips Migrate() when the active provider is SQLite (used by the xUnit integration-test project, which manages its schema with EnsureCreated instead). This prevents conflicts when both host processes — the real API and the test WebApplicationFactory — share the same Startup class.
The BookForm DTO (used as the POST request body for api/libraries/{libraryId}/books) omits libraryId from the body. The library is always taken from the route parameter {libraryId} and assigned to Book.LibraryId by the controller, preventing the client from assigning a book to an arbitrary library. Category is optional in the DTO (string?) and defaults to string.Empty when absent, satisfying the PostgreSQL NOT NULL constraint.

Build docs developers (and LLMs) love