diff --git a/osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs b/osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs
new file mode 100644
index 0000000000..c751530bf4
--- /dev/null
+++ b/osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs
@@ -0,0 +1,293 @@
+//
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage;
+using osu.Game.Database;
+using System;
+
+namespace osu.Game.Migrations
+{
+ [DbContext(typeof(OsuDbContext))]
+ [Migration("20171019041408_InitialCreate")]
+ partial class InitialCreate
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.0.0-rtm-26452");
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ApproachRate");
+
+ b.Property("CircleSize");
+
+ b.Property("DrainRate");
+
+ b.Property("OverallDifficulty");
+
+ b.Property("SliderMultiplier");
+
+ b.Property("SliderTickRate");
+
+ b.HasKey("ID");
+
+ b.ToTable("BeatmapDifficulty");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AudioLeadIn");
+
+ b.Property("BaseDifficultyID");
+
+ b.Property("BeatDivisor");
+
+ b.Property("BeatmapSetInfoID");
+
+ b.Property("Countdown");
+
+ b.Property("DistanceSpacing");
+
+ b.Property("GridSize");
+
+ b.Property("Hash");
+
+ b.Property("Hidden");
+
+ b.Property("LetterboxInBreaks");
+
+ b.Property("MD5Hash");
+
+ b.Property("MetadataID");
+
+ b.Property("OnlineBeatmapID");
+
+ b.Property("Path");
+
+ b.Property("RulesetID");
+
+ b.Property("SpecialStyle");
+
+ b.Property("StackLeniency");
+
+ b.Property("StarDifficulty");
+
+ b.Property("StoredBookmarks");
+
+ b.Property("TimelineZoom");
+
+ b.Property("Version");
+
+ b.Property("WidescreenStoryboard");
+
+ b.HasKey("ID");
+
+ b.HasIndex("BaseDifficultyID");
+
+ b.HasIndex("BeatmapSetInfoID");
+
+ b.HasIndex("Hash");
+
+ b.HasIndex("MD5Hash");
+
+ b.HasIndex("MetadataID");
+
+ b.HasIndex("RulesetID");
+
+ b.ToTable("BeatmapInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Artist");
+
+ b.Property("ArtistUnicode");
+
+ b.Property("AudioFile");
+
+ b.Property("AuthorString")
+ .HasColumnName("Author");
+
+ b.Property("BackgroundFile");
+
+ b.Property("PreviewTime");
+
+ b.Property("Source");
+
+ b.Property("Tags");
+
+ b.Property("Title");
+
+ b.Property("TitleUnicode");
+
+ b.HasKey("ID");
+
+ b.ToTable("BeatmapMetadata");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("BeatmapSetInfoID");
+
+ b.Property("FileInfoID");
+
+ b.Property("Filename")
+ .IsRequired();
+
+ b.HasKey("ID");
+
+ b.HasIndex("BeatmapSetInfoID");
+
+ b.HasIndex("FileInfoID");
+
+ b.ToTable("BeatmapSetFileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("DeletePending");
+
+ b.Property("Hash");
+
+ b.Property("MetadataID");
+
+ b.Property("OnlineBeatmapSetID");
+
+ b.Property("Protected");
+
+ b.HasKey("ID");
+
+ b.HasIndex("DeletePending");
+
+ b.HasIndex("Hash");
+
+ b.HasIndex("MetadataID");
+
+ b.ToTable("BeatmapSetInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("IntAction")
+ .HasColumnName("Action");
+
+ b.Property("KeysString")
+ .HasColumnName("Keys");
+
+ b.Property("RulesetID");
+
+ b.Property("Variant");
+
+ b.HasKey("ID");
+
+ b.HasIndex("IntAction");
+
+ b.HasIndex("Variant");
+
+ b.ToTable("KeyBinding");
+ });
+
+ modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Hash");
+
+ b.Property("ReferenceCount");
+
+ b.HasKey("ID");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("ReferenceCount");
+
+ b.ToTable("FileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Available");
+
+ b.Property("InstantiationInfo");
+
+ b.Property("Name");
+
+ b.HasKey("ID");
+
+ b.HasIndex("Available");
+
+ b.ToTable("RulesetInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
+ .WithMany()
+ .HasForeignKey("BaseDifficultyID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
+ .WithMany("Beatmaps")
+ .HasForeignKey("BeatmapSetInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
+ .WithMany("Beatmaps")
+ .HasForeignKey("MetadataID");
+
+ b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
+ .WithMany()
+ .HasForeignKey("RulesetID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
+ .WithMany("Files")
+ .HasForeignKey("BeatmapSetInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
+ .WithMany()
+ .HasForeignKey("FileInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
+ .WithMany("BeatmapSets")
+ .HasForeignKey("MetadataID");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/osu.Game/Migrations/20171019041408_InitialCreate.cs b/osu.Game/Migrations/20171019041408_InitialCreate.cs
new file mode 100644
index 0000000000..9b6881f98c
--- /dev/null
+++ b/osu.Game/Migrations/20171019041408_InitialCreate.cs
@@ -0,0 +1,311 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace osu.Game.Migrations
+{
+ public partial class InitialCreate : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "BeatmapDifficulty",
+ columns: table => new
+ {
+ ID = table.Column(type: "INTEGER", nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ ApproachRate = table.Column(type: "REAL", nullable: false),
+ CircleSize = table.Column(type: "REAL", nullable: false),
+ DrainRate = table.Column(type: "REAL", nullable: false),
+ OverallDifficulty = table.Column(type: "REAL", nullable: false),
+ SliderMultiplier = table.Column(type: "REAL", nullable: false),
+ SliderTickRate = table.Column(type: "REAL", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_BeatmapDifficulty", x => x.ID);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "BeatmapMetadata",
+ columns: table => new
+ {
+ ID = table.Column(type: "INTEGER", nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Artist = table.Column(type: "TEXT", nullable: true),
+ ArtistUnicode = table.Column(type: "TEXT", nullable: true),
+ AudioFile = table.Column(type: "TEXT", nullable: true),
+ Author = table.Column(type: "TEXT", nullable: true),
+ BackgroundFile = table.Column(type: "TEXT", nullable: true),
+ PreviewTime = table.Column(type: "INTEGER", nullable: false),
+ Source = table.Column(type: "TEXT", nullable: true),
+ Tags = table.Column(type: "TEXT", nullable: true),
+ Title = table.Column(type: "TEXT", nullable: true),
+ TitleUnicode = table.Column(type: "TEXT", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_BeatmapMetadata", x => x.ID);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "FileInfo",
+ columns: table => new
+ {
+ ID = table.Column(type: "INTEGER", nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Hash = table.Column(type: "TEXT", nullable: true),
+ ReferenceCount = table.Column(type: "INTEGER", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_FileInfo", x => x.ID);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "KeyBinding",
+ columns: table => new
+ {
+ ID = table.Column(type: "INTEGER", nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Action = table.Column(type: "INTEGER", nullable: false),
+ Keys = table.Column(type: "TEXT", nullable: true),
+ RulesetID = table.Column(type: "INTEGER", nullable: true),
+ Variant = table.Column(type: "INTEGER", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_KeyBinding", x => x.ID);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "RulesetInfo",
+ columns: table => new
+ {
+ ID = table.Column(type: "INTEGER", nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ Available = table.Column(type: "INTEGER", nullable: false),
+ InstantiationInfo = table.Column(type: "TEXT", nullable: true),
+ Name = table.Column(type: "TEXT", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_RulesetInfo", x => x.ID);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "BeatmapSetInfo",
+ columns: table => new
+ {
+ ID = table.Column(type: "INTEGER", nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ DeletePending = table.Column(type: "INTEGER", nullable: false),
+ Hash = table.Column(type: "TEXT", nullable: true),
+ MetadataID = table.Column(type: "INTEGER", nullable: true),
+ OnlineBeatmapSetID = table.Column(type: "INTEGER", nullable: true),
+ Protected = table.Column(type: "INTEGER", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_BeatmapSetInfo", x => x.ID);
+ table.ForeignKey(
+ name: "FK_BeatmapSetInfo_BeatmapMetadata_MetadataID",
+ column: x => x.MetadataID,
+ principalTable: "BeatmapMetadata",
+ principalColumn: "ID",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "BeatmapInfo",
+ columns: table => new
+ {
+ ID = table.Column(type: "INTEGER", nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ AudioLeadIn = table.Column(type: "INTEGER", nullable: false),
+ BaseDifficultyID = table.Column(type: "INTEGER", nullable: false),
+ BeatDivisor = table.Column(type: "INTEGER", nullable: false),
+ BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: false),
+ Countdown = table.Column(type: "INTEGER", nullable: false),
+ DistanceSpacing = table.Column(type: "REAL", nullable: false),
+ GridSize = table.Column(type: "INTEGER", nullable: false),
+ Hash = table.Column(type: "TEXT", nullable: true),
+ Hidden = table.Column(type: "INTEGER", nullable: false),
+ LetterboxInBreaks = table.Column(type: "INTEGER", nullable: false),
+ MD5Hash = table.Column(type: "TEXT", nullable: true),
+ MetadataID = table.Column(type: "INTEGER", nullable: true),
+ OnlineBeatmapID = table.Column(type: "INTEGER", nullable: true),
+ Path = table.Column(type: "TEXT", nullable: true),
+ RulesetID = table.Column(type: "INTEGER", nullable: false),
+ SpecialStyle = table.Column(type: "INTEGER", nullable: false),
+ StackLeniency = table.Column(type: "REAL", nullable: false),
+ StarDifficulty = table.Column(type: "REAL", nullable: false),
+ StoredBookmarks = table.Column(type: "TEXT", nullable: true),
+ TimelineZoom = table.Column(type: "REAL", nullable: false),
+ Version = table.Column(type: "TEXT", nullable: true),
+ WidescreenStoryboard = table.Column(type: "INTEGER", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_BeatmapInfo", x => x.ID);
+ table.ForeignKey(
+ name: "FK_BeatmapInfo_BeatmapDifficulty_BaseDifficultyID",
+ column: x => x.BaseDifficultyID,
+ principalTable: "BeatmapDifficulty",
+ principalColumn: "ID",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_BeatmapInfo_BeatmapSetInfo_BeatmapSetInfoID",
+ column: x => x.BeatmapSetInfoID,
+ principalTable: "BeatmapSetInfo",
+ principalColumn: "ID",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_BeatmapInfo_BeatmapMetadata_MetadataID",
+ column: x => x.MetadataID,
+ principalTable: "BeatmapMetadata",
+ principalColumn: "ID",
+ onDelete: ReferentialAction.Restrict);
+ table.ForeignKey(
+ name: "FK_BeatmapInfo_RulesetInfo_RulesetID",
+ column: x => x.RulesetID,
+ principalTable: "RulesetInfo",
+ principalColumn: "ID",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "BeatmapSetFileInfo",
+ columns: table => new
+ {
+ ID = table.Column(type: "INTEGER", nullable: false)
+ .Annotation("Sqlite:Autoincrement", true),
+ BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: false),
+ FileInfoID = table.Column(type: "INTEGER", nullable: false),
+ Filename = table.Column(type: "TEXT", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_BeatmapSetFileInfo", x => x.ID);
+ table.ForeignKey(
+ name: "FK_BeatmapSetFileInfo_BeatmapSetInfo_BeatmapSetInfoID",
+ column: x => x.BeatmapSetInfoID,
+ principalTable: "BeatmapSetInfo",
+ principalColumn: "ID",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_BeatmapSetFileInfo_FileInfo_FileInfoID",
+ column: x => x.FileInfoID,
+ principalTable: "FileInfo",
+ principalColumn: "ID",
+ onDelete: ReferentialAction.Cascade);
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapInfo_BaseDifficultyID",
+ table: "BeatmapInfo",
+ column: "BaseDifficultyID");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapInfo_BeatmapSetInfoID",
+ table: "BeatmapInfo",
+ column: "BeatmapSetInfoID");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapInfo_Hash",
+ table: "BeatmapInfo",
+ column: "Hash");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapInfo_MD5Hash",
+ table: "BeatmapInfo",
+ column: "MD5Hash");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapInfo_MetadataID",
+ table: "BeatmapInfo",
+ column: "MetadataID");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapInfo_RulesetID",
+ table: "BeatmapInfo",
+ column: "RulesetID");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapSetFileInfo_BeatmapSetInfoID",
+ table: "BeatmapSetFileInfo",
+ column: "BeatmapSetInfoID");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapSetFileInfo_FileInfoID",
+ table: "BeatmapSetFileInfo",
+ column: "FileInfoID");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapSetInfo_DeletePending",
+ table: "BeatmapSetInfo",
+ column: "DeletePending");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapSetInfo_Hash",
+ table: "BeatmapSetInfo",
+ column: "Hash");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapSetInfo_MetadataID",
+ table: "BeatmapSetInfo",
+ column: "MetadataID");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_FileInfo_Hash",
+ table: "FileInfo",
+ column: "Hash",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_FileInfo_ReferenceCount",
+ table: "FileInfo",
+ column: "ReferenceCount");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_KeyBinding_Action",
+ table: "KeyBinding",
+ column: "Action");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_KeyBinding_Variant",
+ table: "KeyBinding",
+ column: "Variant");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_RulesetInfo_Available",
+ table: "RulesetInfo",
+ column: "Available");
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "BeatmapInfo");
+
+ migrationBuilder.DropTable(
+ name: "BeatmapSetFileInfo");
+
+ migrationBuilder.DropTable(
+ name: "KeyBinding");
+
+ migrationBuilder.DropTable(
+ name: "BeatmapDifficulty");
+
+ migrationBuilder.DropTable(
+ name: "RulesetInfo");
+
+ migrationBuilder.DropTable(
+ name: "BeatmapSetInfo");
+
+ migrationBuilder.DropTable(
+ name: "FileInfo");
+
+ migrationBuilder.DropTable(
+ name: "BeatmapMetadata");
+ }
+ }
+}
diff --git a/osu.Game/Migrations/20171025071459_AddMissingIndexRules.Designer.cs b/osu.Game/Migrations/20171025071459_AddMissingIndexRules.Designer.cs
new file mode 100644
index 0000000000..4cd234f2ef
--- /dev/null
+++ b/osu.Game/Migrations/20171025071459_AddMissingIndexRules.Designer.cs
@@ -0,0 +1,299 @@
+//
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage;
+using osu.Game.Database;
+using System;
+
+namespace osu.Game.Migrations
+{
+ [DbContext(typeof(OsuDbContext))]
+ [Migration("20171025071459_AddMissingIndexRules")]
+ partial class AddMissingIndexRules
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.0.0-rtm-26452");
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ApproachRate");
+
+ b.Property("CircleSize");
+
+ b.Property("DrainRate");
+
+ b.Property("OverallDifficulty");
+
+ b.Property("SliderMultiplier");
+
+ b.Property("SliderTickRate");
+
+ b.HasKey("ID");
+
+ b.ToTable("BeatmapDifficulty");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AudioLeadIn");
+
+ b.Property("BaseDifficultyID");
+
+ b.Property("BeatDivisor");
+
+ b.Property("BeatmapSetInfoID");
+
+ b.Property("Countdown");
+
+ b.Property("DistanceSpacing");
+
+ b.Property("GridSize");
+
+ b.Property("Hash");
+
+ b.Property("Hidden");
+
+ b.Property("LetterboxInBreaks");
+
+ b.Property("MD5Hash");
+
+ b.Property("MetadataID");
+
+ b.Property("OnlineBeatmapID");
+
+ b.Property("Path");
+
+ b.Property("RulesetID");
+
+ b.Property("SpecialStyle");
+
+ b.Property("StackLeniency");
+
+ b.Property("StarDifficulty");
+
+ b.Property("StoredBookmarks");
+
+ b.Property("TimelineZoom");
+
+ b.Property("Version");
+
+ b.Property("WidescreenStoryboard");
+
+ b.HasKey("ID");
+
+ b.HasIndex("BaseDifficultyID");
+
+ b.HasIndex("BeatmapSetInfoID");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("MD5Hash")
+ .IsUnique();
+
+ b.HasIndex("MetadataID");
+
+ b.HasIndex("RulesetID");
+
+ b.ToTable("BeatmapInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Artist");
+
+ b.Property("ArtistUnicode");
+
+ b.Property("AudioFile");
+
+ b.Property("AuthorString")
+ .HasColumnName("Author");
+
+ b.Property("BackgroundFile");
+
+ b.Property("PreviewTime");
+
+ b.Property("Source");
+
+ b.Property("Tags");
+
+ b.Property("Title");
+
+ b.Property("TitleUnicode");
+
+ b.HasKey("ID");
+
+ b.ToTable("BeatmapMetadata");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("BeatmapSetInfoID");
+
+ b.Property("FileInfoID");
+
+ b.Property("Filename")
+ .IsRequired();
+
+ b.HasKey("ID");
+
+ b.HasIndex("BeatmapSetInfoID");
+
+ b.HasIndex("FileInfoID");
+
+ b.ToTable("BeatmapSetFileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("DeletePending");
+
+ b.Property("Hash");
+
+ b.Property("MetadataID");
+
+ b.Property("OnlineBeatmapSetID");
+
+ b.Property("Protected");
+
+ b.HasKey("ID");
+
+ b.HasIndex("DeletePending");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("MetadataID");
+
+ b.HasIndex("OnlineBeatmapSetID")
+ .IsUnique();
+
+ b.ToTable("BeatmapSetInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("IntAction")
+ .HasColumnName("Action");
+
+ b.Property("KeysString")
+ .HasColumnName("Keys");
+
+ b.Property("RulesetID");
+
+ b.Property("Variant");
+
+ b.HasKey("ID");
+
+ b.HasIndex("IntAction");
+
+ b.HasIndex("Variant");
+
+ b.ToTable("KeyBinding");
+ });
+
+ modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Hash");
+
+ b.Property("ReferenceCount");
+
+ b.HasKey("ID");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("ReferenceCount");
+
+ b.ToTable("FileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Available");
+
+ b.Property("InstantiationInfo");
+
+ b.Property("Name");
+
+ b.HasKey("ID");
+
+ b.HasIndex("Available");
+
+ b.ToTable("RulesetInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
+ .WithMany()
+ .HasForeignKey("BaseDifficultyID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
+ .WithMany("Beatmaps")
+ .HasForeignKey("BeatmapSetInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
+ .WithMany("Beatmaps")
+ .HasForeignKey("MetadataID");
+
+ b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
+ .WithMany()
+ .HasForeignKey("RulesetID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
+ .WithMany("Files")
+ .HasForeignKey("BeatmapSetInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
+ .WithMany()
+ .HasForeignKey("FileInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
+ .WithMany("BeatmapSets")
+ .HasForeignKey("MetadataID");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs b/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs
new file mode 100644
index 0000000000..c9fc59c5a2
--- /dev/null
+++ b/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs
@@ -0,0 +1,80 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace osu.Game.Migrations
+{
+ public partial class AddMissingIndexRules : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "IX_BeatmapSetInfo_Hash",
+ table: "BeatmapSetInfo");
+
+ migrationBuilder.DropIndex(
+ name: "IX_BeatmapInfo_Hash",
+ table: "BeatmapInfo");
+
+ migrationBuilder.DropIndex(
+ name: "IX_BeatmapInfo_MD5Hash",
+ table: "BeatmapInfo");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapSetInfo_Hash",
+ table: "BeatmapSetInfo",
+ column: "Hash",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapSetInfo_OnlineBeatmapSetID",
+ table: "BeatmapSetInfo",
+ column: "OnlineBeatmapSetID",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapInfo_Hash",
+ table: "BeatmapInfo",
+ column: "Hash",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapInfo_MD5Hash",
+ table: "BeatmapInfo",
+ column: "MD5Hash",
+ unique: true);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "IX_BeatmapSetInfo_Hash",
+ table: "BeatmapSetInfo");
+
+ migrationBuilder.DropIndex(
+ name: "IX_BeatmapSetInfo_OnlineBeatmapSetID",
+ table: "BeatmapSetInfo");
+
+ migrationBuilder.DropIndex(
+ name: "IX_BeatmapInfo_Hash",
+ table: "BeatmapInfo");
+
+ migrationBuilder.DropIndex(
+ name: "IX_BeatmapInfo_MD5Hash",
+ table: "BeatmapInfo");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapSetInfo_Hash",
+ table: "BeatmapSetInfo",
+ column: "Hash");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapInfo_Hash",
+ table: "BeatmapInfo",
+ column: "Hash");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapInfo_MD5Hash",
+ table: "BeatmapInfo",
+ column: "MD5Hash");
+ }
+ }
+}
diff --git a/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs
new file mode 100644
index 0000000000..006acf12cd
--- /dev/null
+++ b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs
@@ -0,0 +1,302 @@
+//
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage;
+using osu.Game.Database;
+using System;
+
+namespace osu.Game.Migrations
+{
+ [DbContext(typeof(OsuDbContext))]
+ [Migration("20171119065731_AddBeatmapOnlineIDUniqueConstraint")]
+ partial class AddBeatmapOnlineIDUniqueConstraint
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.0.0-rtm-26452");
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ApproachRate");
+
+ b.Property("CircleSize");
+
+ b.Property("DrainRate");
+
+ b.Property("OverallDifficulty");
+
+ b.Property("SliderMultiplier");
+
+ b.Property("SliderTickRate");
+
+ b.HasKey("ID");
+
+ b.ToTable("BeatmapDifficulty");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AudioLeadIn");
+
+ b.Property("BaseDifficultyID");
+
+ b.Property("BeatDivisor");
+
+ b.Property("BeatmapSetInfoID");
+
+ b.Property("Countdown");
+
+ b.Property("DistanceSpacing");
+
+ b.Property("GridSize");
+
+ b.Property("Hash");
+
+ b.Property("Hidden");
+
+ b.Property("LetterboxInBreaks");
+
+ b.Property("MD5Hash");
+
+ b.Property("MetadataID");
+
+ b.Property("OnlineBeatmapID");
+
+ b.Property("Path");
+
+ b.Property("RulesetID");
+
+ b.Property("SpecialStyle");
+
+ b.Property("StackLeniency");
+
+ b.Property("StarDifficulty");
+
+ b.Property("StoredBookmarks");
+
+ b.Property("TimelineZoom");
+
+ b.Property("Version");
+
+ b.Property("WidescreenStoryboard");
+
+ b.HasKey("ID");
+
+ b.HasIndex("BaseDifficultyID");
+
+ b.HasIndex("BeatmapSetInfoID");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("MD5Hash")
+ .IsUnique();
+
+ b.HasIndex("MetadataID");
+
+ b.HasIndex("OnlineBeatmapID")
+ .IsUnique();
+
+ b.HasIndex("RulesetID");
+
+ b.ToTable("BeatmapInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Artist");
+
+ b.Property("ArtistUnicode");
+
+ b.Property("AudioFile");
+
+ b.Property("AuthorString")
+ .HasColumnName("Author");
+
+ b.Property("BackgroundFile");
+
+ b.Property("PreviewTime");
+
+ b.Property("Source");
+
+ b.Property("Tags");
+
+ b.Property("Title");
+
+ b.Property("TitleUnicode");
+
+ b.HasKey("ID");
+
+ b.ToTable("BeatmapMetadata");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("BeatmapSetInfoID");
+
+ b.Property("FileInfoID");
+
+ b.Property("Filename")
+ .IsRequired();
+
+ b.HasKey("ID");
+
+ b.HasIndex("BeatmapSetInfoID");
+
+ b.HasIndex("FileInfoID");
+
+ b.ToTable("BeatmapSetFileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("DeletePending");
+
+ b.Property("Hash");
+
+ b.Property("MetadataID");
+
+ b.Property("OnlineBeatmapSetID");
+
+ b.Property("Protected");
+
+ b.HasKey("ID");
+
+ b.HasIndex("DeletePending");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("MetadataID");
+
+ b.HasIndex("OnlineBeatmapSetID")
+ .IsUnique();
+
+ b.ToTable("BeatmapSetInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("IntAction")
+ .HasColumnName("Action");
+
+ b.Property("KeysString")
+ .HasColumnName("Keys");
+
+ b.Property("RulesetID");
+
+ b.Property("Variant");
+
+ b.HasKey("ID");
+
+ b.HasIndex("IntAction");
+
+ b.HasIndex("Variant");
+
+ b.ToTable("KeyBinding");
+ });
+
+ modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Hash");
+
+ b.Property("ReferenceCount");
+
+ b.HasKey("ID");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("ReferenceCount");
+
+ b.ToTable("FileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Available");
+
+ b.Property("InstantiationInfo");
+
+ b.Property("Name");
+
+ b.HasKey("ID");
+
+ b.HasIndex("Available");
+
+ b.ToTable("RulesetInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
+ .WithMany()
+ .HasForeignKey("BaseDifficultyID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
+ .WithMany("Beatmaps")
+ .HasForeignKey("BeatmapSetInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
+ .WithMany("Beatmaps")
+ .HasForeignKey("MetadataID");
+
+ b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
+ .WithMany()
+ .HasForeignKey("RulesetID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
+ .WithMany("Files")
+ .HasForeignKey("BeatmapSetInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
+ .WithMany()
+ .HasForeignKey("FileInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
+ .WithMany("BeatmapSets")
+ .HasForeignKey("MetadataID");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs
new file mode 100644
index 0000000000..084ae67940
--- /dev/null
+++ b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs
@@ -0,0 +1,23 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace osu.Game.Migrations
+{
+ public partial class AddBeatmapOnlineIDUniqueConstraint : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateIndex(
+ name: "IX_BeatmapInfo_OnlineBeatmapID",
+ table: "BeatmapInfo",
+ column: "OnlineBeatmapID",
+ unique: true);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropIndex(
+ name: "IX_BeatmapInfo_OnlineBeatmapID",
+ table: "BeatmapInfo");
+ }
+ }
+}
diff --git a/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.Designer.cs b/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.Designer.cs
new file mode 100644
index 0000000000..fc2496bc24
--- /dev/null
+++ b/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.Designer.cs
@@ -0,0 +1,307 @@
+//
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage;
+using osu.Game.Database;
+using System;
+
+namespace osu.Game.Migrations
+{
+ [DbContext(typeof(OsuDbContext))]
+ [Migration("20171209034410_AddRulesetInfoShortName")]
+ partial class AddRulesetInfoShortName
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.0.0-rtm-26452");
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ApproachRate");
+
+ b.Property