Files
maraphon-app/src/Marathon.Infrastructure/Migrations/20260505000000_InitialCreate.cs
T
alexei.dolgolyov 85bc99cac5 fix(host): wire DB migration init + Plotly CDN + attribute fix on hand-written migration
Three fixes surfaced when launching the WPF host for the first time:

1. App.xaml.cs — call MarathonDbContextInitializer.InitializeAsync()
   between Host.Build() and Host.Start() so EF migrations + WAL pragma
   are applied BEFORE BackgroundServices race to query the DB. Without
   this, all pollers crashed on 'no such table: Events'.

2. wwwroot/index.html — added <script src='https://cdn.plot.ly/plotly-2.35.2.min.js'>
   before blazor.webview.js. Phase 6 reviewer flagged this for Phase 9,
   but charts are unrenderable without it; better to ship now.

3. Migrations/20260505000000_InitialCreate.cs — added [DbContext] and
   [Migration('20260505000000_InitialCreate')] attributes. Phase 2's
   hand-written migration was missing both, so EF saw 'no migrations to
   apply' even on a fresh DB. With the attributes, the migration runs
   on first launch and creates all tables (Events, Snapshots, Bets,
   EventResults, Anomalies, Sports, Leagues).

Verified: clean DB → migration applied → all 7 tables created → pollers
run with empty results (no data yet — UpcomingEventsPoller fires every 6h
by default; first scrape will populate the DB).
2026-05-05 13:55:59 +03:00

192 lines
7.8 KiB
C#

using Marathon.Infrastructure.Persistence;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Marathon.Infrastructure.Migrations;
/// <inheritdoc />
[DbContext(typeof(MarathonDbContext))]
[Migration("20260505000000_InitialCreate")]
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Events",
columns: table => new
{
EventCode = table.Column<string>(type: "TEXT", nullable: false),
SportCode = table.Column<int>(type: "INTEGER", nullable: false),
CountryCode = table.Column<string>(type: "TEXT", nullable: false),
LeagueId = table.Column<string>(type: "TEXT", nullable: false),
Category = table.Column<string>(type: "TEXT", nullable: false, defaultValue: ""),
ScheduledAt = table.Column<string>(type: "TEXT", nullable: false),
Side1Name = table.Column<string>(type: "TEXT", nullable: false),
Side2Name = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Events", x => x.EventCode);
});
migrationBuilder.CreateTable(
name: "Leagues",
columns: table => new
{
Id = table.Column<string>(type: "TEXT", nullable: false),
SportCode = table.Column<int>(type: "INTEGER", nullable: false),
Country = table.Column<string>(type: "TEXT", nullable: false),
NameRu = table.Column<string>(type: "TEXT", nullable: false),
NameEn = table.Column<string>(type: "TEXT", nullable: false),
Category = table.Column<string>(type: "TEXT", nullable: false, defaultValue: "")
},
constraints: table =>
{
table.PrimaryKey("PK_Leagues", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Sports",
columns: table => new
{
Code = table.Column<int>(type: "INTEGER", nullable: false),
NameRu = table.Column<string>(type: "TEXT", nullable: false),
NameEn = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Sports", x => x.Code);
});
migrationBuilder.CreateTable(
name: "Anomalies",
columns: table => new
{
Id = table.Column<string>(type: "TEXT", nullable: false),
EventCode = table.Column<string>(type: "TEXT", nullable: false),
DetectedAt = table.Column<string>(type: "TEXT", nullable: false),
Kind = table.Column<int>(type: "INTEGER", nullable: false),
Score = table.Column<decimal>(type: "TEXT", nullable: false),
EvidenceJson = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Anomalies", x => x.Id);
table.ForeignKey(
name: "FK_Anomalies_Events_EventCode",
column: x => x.EventCode,
principalTable: "Events",
principalColumn: "EventCode",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "EventResults",
columns: table => new
{
EventCode = table.Column<string>(type: "TEXT", nullable: false),
Side1Score = table.Column<int>(type: "INTEGER", nullable: false),
Side2Score = table.Column<int>(type: "INTEGER", nullable: false),
WinnerSide = table.Column<int>(type: "INTEGER", nullable: false),
CompletedAt = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_EventResults", x => x.EventCode);
table.ForeignKey(
name: "FK_EventResults_Events_EventCode",
column: x => x.EventCode,
principalTable: "Events",
principalColumn: "EventCode",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Snapshots",
columns: table => new
{
Id = table.Column<long>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
EventCode = table.Column<string>(type: "TEXT", nullable: false),
CapturedAt = table.Column<string>(type: "TEXT", nullable: false),
Source = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Snapshots", x => x.Id);
table.ForeignKey(
name: "FK_Snapshots_Events_EventCode",
column: x => x.EventCode,
principalTable: "Events",
principalColumn: "EventCode",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Bets",
columns: table => new
{
Id = table.Column<long>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
SnapshotId = table.Column<long>(type: "INTEGER", nullable: false),
Scope = table.Column<int>(type: "INTEGER", nullable: false),
PeriodNumber = table.Column<int>(type: "INTEGER", nullable: true),
Type = table.Column<int>(type: "INTEGER", nullable: false),
Side = table.Column<int>(type: "INTEGER", nullable: false),
Value = table.Column<decimal>(type: "TEXT", nullable: true),
Rate = table.Column<decimal>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Bets", x => x.Id);
table.ForeignKey(
name: "FK_Bets_Snapshots_SnapshotId",
column: x => x.SnapshotId,
principalTable: "Snapshots",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
// Indexes
migrationBuilder.CreateIndex(
name: "IX_Events_SportCode_ScheduledAt",
table: "Events",
columns: new[] { "SportCode", "ScheduledAt" });
migrationBuilder.CreateIndex(
name: "IX_Events_ScheduledAt",
table: "Events",
column: "ScheduledAt");
migrationBuilder.CreateIndex(
name: "IX_Snapshots_EventCode",
table: "Snapshots",
column: "EventCode");
migrationBuilder.CreateIndex(
name: "IX_Bets_SnapshotId",
table: "Bets",
column: "SnapshotId");
migrationBuilder.CreateIndex(
name: "IX_Anomalies_EventCode",
table: "Anomalies",
column: "EventCode");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "Bets");
migrationBuilder.DropTable(name: "Snapshots");
migrationBuilder.DropTable(name: "EventResults");
migrationBuilder.DropTable(name: "Anomalies");
migrationBuilder.DropTable(name: "Events");
migrationBuilder.DropTable(name: "Leagues");
migrationBuilder.DropTable(name: "Sports");
}
}