f294255f10
- Add IEventRepository/IResultRepository.GetManyAsync to kill N+1 lookups at 6 sites (backtest, outcome eval, both bet-journal paths, anomaly browsing, results selection); guarded by a Received(1).GetManyAsync test. - Add EventRepository.QueryAsync to push date+sport filtering to SQL (was load-whole-range-then-filter); search/sort stay in-memory for Cyrillic order. - Add AnomalyRepository.CountSinceAsync (unread badge) + ListByDateRangeAsync (feed date filter); add Event/Snapshot count methods for the dashboard. - Add composite indexes IX_Snapshots_EventCode_CapturedAt and _EventCode_Source_CapturedAt via a new migration + model snapshot. - Introduce SqliteDateText as the single source of the O-format date encoding shared by Mapping (read/write) and the repositories' range predicates. - Fix LiveOddsPoller cadence drift (budget sleep against cycle time); make DetectAnomalies dedup O(1) per event; add Event.Title to dedup the title join. Tests adapted to the batched GetManyAsync via a TestFixtures bridge.
38 lines
1.7 KiB
C#
38 lines
1.7 KiB
C#
using Marathon.Infrastructure.Persistence.Entities;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||
|
||
namespace Marathon.Infrastructure.Persistence.Configurations;
|
||
|
||
internal sealed class SnapshotConfiguration : IEntityTypeConfiguration<SnapshotEntity>
|
||
{
|
||
public void Configure(EntityTypeBuilder<SnapshotEntity> builder)
|
||
{
|
||
builder.ToTable("Snapshots");
|
||
|
||
builder.HasKey(s => s.Id);
|
||
builder.Property(s => s.Id).HasColumnType("INTEGER").ValueGeneratedOnAdd();
|
||
builder.Property(s => s.EventCode).HasColumnType("TEXT").IsRequired();
|
||
builder.Property(s => s.CapturedAt).HasColumnType("TEXT").IsRequired();
|
||
builder.Property(s => s.Source).HasColumnType("INTEGER").IsRequired();
|
||
|
||
builder.HasIndex(s => s.EventCode).HasDatabaseName("IX_Snapshots_EventCode");
|
||
|
||
// Snapshots is the largest table (live cadence 5–10s, 90-day retention) and
|
||
// every hot read filters EventCode + CapturedAt range, often with an ORDER BY
|
||
// CapturedAt. These composite indexes let SQLite satisfy the filter and the
|
||
// ordering from the index instead of scanning + sorting the table.
|
||
builder.HasIndex(s => new { s.EventCode, s.CapturedAt })
|
||
.HasDatabaseName("IX_Snapshots_EventCode_CapturedAt");
|
||
|
||
// Covers GetLatestPreMatchAsync: EventCode + Source filter, ORDER BY CapturedAt DESC.
|
||
builder.HasIndex(s => new { s.EventCode, s.Source, s.CapturedAt })
|
||
.HasDatabaseName("IX_Snapshots_EventCode_Source_CapturedAt");
|
||
|
||
builder.HasMany(s => s.Bets)
|
||
.WithOne(b => b.Snapshot)
|
||
.HasForeignKey(b => b.SnapshotId)
|
||
.OnDelete(DeleteBehavior.Cascade);
|
||
}
|
||
}
|