85bc99cac5
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).
192 lines
7.8 KiB
C#
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");
|
|
}
|
|
}
|