Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 7 additions & 8 deletions dotnet-efcore/RevertMigration/Migrations/20231209224404_Init.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
HangarNumber = table.Column<string>(type: "TEXT", nullable: false)
HangarNumber = table.Column<string>(type: "TEXT", nullable: true)
},
constraints: table =>
{
Expand All @@ -29,11 +29,11 @@ protected override void Up(MigrationBuilder migrationBuilder)
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
TailNumber = table.Column<string>(type: "TEXT", nullable: false),
NumberOfEngines = table.Column<int>(type: "INTEGER", nullable: false),
MaxAirSpeed = table.Column<double>(type: "REAL", nullable: false),
RunsOnJetFuel = table.Column<bool>(type: "INTEGER", nullable: false),
HangarId = table.Column<int>(type: "INTEGER", nullable: false)
TailNumber = table.Column<string>(type: "TEXT", nullable: true),
NumberOfEngines = table.Column<int>(type: "INTEGER", nullable: true),
MaxAirSpeed = table.Column<double>(type: "REAL", nullable: true),
RunsOnJetFuel = table.Column<bool>(type: "INTEGER", nullable: true),
HangarId = table.Column<int>(type: "INTEGER", nullable: true)
},
constraints: table =>
{
Expand All @@ -42,8 +42,7 @@ protected override void Up(MigrationBuilder migrationBuilder)
name: "FK_Airplanes_Hangars_HangarId",
column: x => x.HangarId,
principalTable: "Hangars",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
principalColumn: "Id");
});

migrationBuilder.CreateIndex(
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace RevertMigration.Migrations
{
/// <inheritdoc />
public partial class Hangar_HasDoors : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "HasDoors",
table: "Hangars",
type: "INTEGER",
nullable: false,
defaultValue: false);
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "HasDoors",
table: "Hangars");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,34 @@ partial class AirportDbContextModelSnapshot : ModelSnapshot
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.0");
modelBuilder.HasAnnotation("ProductVersion", "10.0.12");

modelBuilder.Entity("Airplane", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");

b.Property<int>("HangarId")
b.Property<int?>("HangarId")
.HasColumnType("INTEGER");

b.Property<double>("MaxAirSpeed")
b.Property<double?>("MaxAirSpeed")
.HasColumnType("REAL");

b.Property<int>("NumberOfEngines")
b.Property<int?>("NumberOfEngines")
.HasColumnType("INTEGER");

b.Property<bool>("RunsOnJetFuel")
b.Property<bool?>("RunsOnJetFuel")
.HasColumnType("INTEGER");

b.Property<string>("TailNumber")
.IsRequired()
.HasColumnType("TEXT");

b.HasKey("Id");

b.HasIndex("HangarId");

b.ToTable("Airplanes", (string)null);
b.ToTable("Airplanes");
});

modelBuilder.Entity("Hangar", b =>
Expand All @@ -51,21 +50,21 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.HasColumnType("INTEGER");

b.Property<string>("HangarNumber")
.IsRequired()
.HasColumnType("TEXT");

b.Property<bool>("HasDoors")
.HasColumnType("INTEGER");

b.HasKey("Id");

b.ToTable("Hangars", (string)null);
b.ToTable("Hangars");
});

modelBuilder.Entity("Airplane", b =>
{
b.HasOne("Hangar", "Hangar")
.WithMany("Airplanes")
.HasForeignKey("HangarId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
.HasForeignKey("HangarId");

b.Navigation("Hangar");
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;

public class MigrationRevertTests : IDisposable
{
private const string InitMigration = "20231209224404_Init";
private const string HasDoorsMigration = "20231209231131_Hangar_HasDoors";

private readonly string _dbPath = Path.Combine(Path.GetTempPath(), $"airport-{Guid.NewGuid():N}.db");

private AirportDbContext CreateContext()
{
// The sample keeps its database in LocalApplicationData; the tests use a throwaway file instead.
var db = new AirportDbContext();
db.Database.SetConnectionString($"Data Source={_dbPath}");

return db;
}

private static List<string> GetHangarColumns(AirportDbContext db)
{
var connection = db.Database.GetDbConnection();
connection.Open();
try
{
using var command = connection.CreateCommand();
command.CommandText = "SELECT name FROM pragma_table_info('Hangars');";
using var reader = command.ExecuteReader();

var columns = new List<string>();
while (reader.Read())
{
columns.Add(reader.GetString(0));
}

return columns;
}
finally
{
connection.Close();
}
}

[Fact]
public void WhenAllMigrationsAreApplied_ThenHangarsHasTheHasDoorsColumn()
{
using var db = CreateContext();

db.Database.Migrate();

Assert.Equal([InitMigration, HasDoorsMigration], db.Database.GetAppliedMigrations());
Assert.Contains("HasDoors", GetHangarColumns(db));
}

[Fact]
public void WhenAllMigrationsAreApplied_ThenTheSampleCanSaveAHangarWithDoors()
{
using (var db = CreateContext())
{
db.Database.Migrate();
db.Add(new Hangar { HangarNumber = "HANGAR_01", HasDoors = true });
db.SaveChanges();
}

using (var db = CreateContext())
{
var hangar = db.Hangars.Single();

Assert.Equal("HANGAR_01", hangar.HangarNumber);
Assert.True(hangar.HasDoors);
}
}

[Fact]
public void WhenDatabaseIsUpdatedToInit_ThenTheHasDoorsColumnIsGone()
{
using var db = CreateContext();
db.Database.Migrate();

db.GetService<IMigrator>().Migrate(InitMigration);

Assert.Equal([InitMigration], db.Database.GetAppliedMigrations());
Assert.Equal([HasDoorsMigration], db.Database.GetPendingMigrations());
Assert.DoesNotContain("HasDoors", GetHangarColumns(db));
}

[Fact]
public void WhenDatabaseIsUpdatedToZero_ThenEveryMigrationIsReverted()
{
using var db = CreateContext();
db.Database.Migrate();

db.GetService<IMigrator>().Migrate(Migration.InitialDatabase);

Assert.Empty(db.Database.GetAppliedMigrations());
Assert.Empty(GetHangarColumns(db));
}

public void Dispose()
{
SqliteConnection.ClearAllPools();
File.Delete(_dbPath);
}
}
Loading
Loading