Entity Framework creates migration without any updates
Asked Answered
M

1

10

At the moment, I'm experiencing an issue where I can create a migration, which has data updates, but the DbContextModelSnapshot has this data. When you look at the updates in the migration, they've already been applied to the DbContextModelSnapshot and the database.

A coworker created a migration about 3 months ago, and everything has been fine. We've created several more migrations since then, and haven't experienced this issue. However, the last couple days, we have been experiencing this.

We've tried creating a migration with this data update, and running it. But when we create another migration, that data update is there again. None of us have experienced this issue before.

How can we create migrations without having this data keep showing up? I'm not sure what code would be relevant to show for this.

EDIT:

Migrations are created that have Data A (pre-existing data in the database and DbContextModelSnapshot) and Data B (new Data), and are completely successfully. By that, I mean that Data B is added to the database and the DbContextModelSnapshot without issue. However, when I create another migration, Data A shows up again.

EDIT 2:

As requested, I've looked at all the migrations we have and compared to the __EFMigrationsHistory, and they are all there. Every migration has been run successfully. This was verified by at least 3 people.

EDIT 3:

Okay, the question asked was how am I specifying the data for the migrations. In the model class, we've got our Configure(). Here's it, and the subsequent functions:

internal static void Configure(EntityTypeBuilder<PlayerType> entityTypeBuilder)
{
    SetDefaultValues(entityTypeBuilder);
    LoadSeedData(entityTypeBuilder);
}

private static void LoadSeedData(EntityTypeBuilder<PlayerType> entityTypeBuilder)
{
    void AddPlayerType(int playerTypeId, string name, DateTime createdDate, DateTime? modifiedDate = null, bool isSystemDefault = true)
    {
        entityTypeBuilder
            .HasData(
                DbContextHelper.AssignBaseStats(
                    new List<PlayerType>
                    {
                        new PlayerType()
                        {
                            PlayerTypeId = playerTypeId,
                            Name             = name,
                            IsSystemDefault = isSystemDefault
                        },
                    },
                    createdDate,
                    !modifiedDate.HasValue ? createdDate : modifiedDate.Value,
                    ApplicationConstants.SeedDataGenerationIdentifier,
                    false));
    }

    AddPlayerType(ApplicationConstants.TitleId, "Title", new DateTime(2020, 2, 11, 16, 27, 0, 0, DateTimeKind.Utc),
                        new DateTime(2020, 12, 19, 20, 11, 0, 0, DateTimeKind.Utc));
    AddPlayerType(ApplicationConstants.BaseId, "Base", new DateTime(2020, 2, 11, 16, 27, 0, 0, DateTimeKind.Utc),
                        new DateTime(2020, 12, 19, 20, 11, 0, 0, DateTimeKind.Utc));
    AddPlayerType(ApplicationConstants.QuizId, "Quiz", new DateTime(2020, 2, 11, 16, 27, 0, 0, DateTimeKind.Utc),
                        new DateTime(2020, 12, 19, 20, 11, 0, 0, DateTimeKind.Utc));
    AddPlayerType(ApplicationConstants.ThreeDId, "ThreeDModel", new DateTime(2020, 2, 11, 16, 27, 0, 0, DateTimeKind.Utc),
                        new DateTime(2020, 12, 19, 20, 11, 0, 0, DateTimeKind.Utc), false);
    AddPlayerType(ApplicationConstants.TestId, "Test", new DateTime(2020, 2, 11, 16, 27, 0, 0, DateTimeKind.Utc),
                        new DateTime(2020, 12, 19, 20, 11, 0, 0, DateTimeKind.Utc), false);
    AddPlayerType(ApplicationConstants.ScoreId, "Score", new DateTime(2020, 3, 25, 21, 59, 0, 0, DateTimeKind.Utc),
                        new DateTime(2020, 12, 19, 20, 11, 0, 0, DateTimeKind.Utc));
    AddPlayerType(ApplicationConstants.ExitId, "Exit", new DateTime(2020, 3, 25, 21, 59, 0, 0, DateTimeKind.Utc),
                        new DateTime(2020, 12, 19, 20, 11, 0, 0, DateTimeKind.Utc));
    AddPlayerType(ApplicationConstants.WalkId, "Walkaround", new DateTime(2020, 10, 22, 14, 44, 0, 0, DateTimeKind.Utc),
                        new DateTime(2020, 12, 19, 20, 11, 0, 0, DateTimeKind.Utc), false);
}

private static void SetDefaultValues(EntityTypeBuilder<PlayerType> entityTypeBuilder)
{
    entityTypeBuilder
        .Property(thisTable => thisTable.IsSystemDefault)
        .HasDefaultValue(false);
}

Now, this was updated back in mid-December, and all migrations after have been fine. But as stated, recent migrations have started having the following:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.UpdateData(
        schema: "LessonDesigner",
        table: "PlayerType",
        keyColumn: "PlayerTypeId",
        keyValue: 1,
        column: "IsSystemDefault",
        value: true);

    migrationBuilder.UpdateData(
        schema: "LessonDesigner",
        table: "PlayerType",
        keyColumn: "PlayerTypeId",
        keyValue: 2,
        column: "IsSystemDefault",
        value: true);

    migrationBuilder.UpdateData(
        schema: "LessonDesigner",
        table: "PlayerType",
        keyColumn: "PlayerTypeId",
        keyValue: 3,
        column: "IsSystemDefault",
        value: true);

    migrationBuilder.UpdateData(
        schema: "LessonDesigner",
        table: "PlayerType",
        keyColumn: "PlayerTypeId",
        keyValue: 6,
        column: "IsSystemDefault",
        value: true);

    migrationBuilder.UpdateData(
        schema: "LessonDesigner",
        table: "PlayerType",
        keyColumn: "PlayerTypeId",
        keyValue: 7,
        column: "IsSystemDefault",
        value: true);
}

EDIT 4:

Here's screenshots to show the back-to-back created migrations. You can see, the Up() is identical:

enter image description here

enter image description here

Mattock answered 25/1, 2021 at 18:10 Comment(12)
are you sure the transactions are being closed? maybe you have a deadlock that causes the transaction to roll back or not complete.Dogwood
@Hogan: But if it rolled back, wouldn't that prevent any future migrations from completing successfully?Mattock
I've no idea how you "migrations" work - so I can't say -- what I hear is you did some database transactions and you don't see them commuted to the db. I'm suggesting some reasons why. For more understanding I'd have to see more of your code and get into some specifics.Dogwood
Could you please compare the migrations in your Migrations folder with records of your __EFMigrationsHistory table and update your question with results.Kab
A bounty won't help you get answers. A clearer description and adding a minimal reproducible example will. Esp. the phrase "the DbContext isn't being updated" is not clear. Migrations don't "update a context". What do you mean? You really have to show an example that reproduces and demonstrates the issue.Huambo
@GertArnold I'm not really sure what code I could add that would be reproducable for this. Simply every time we create a migration, this data update is added, and it doesn't need to be. Also, I'll update, because that phrase you mentioned I can agree is a bit incorrect.Mattock
How are you specifying the data to be added in the migrations?Tahmosh
PiousVenom, for sake of rigor: please make 2 migrations, one after the other and run a diff against them. Are they 100% identical? This is a truly bizarre issue if they are.Allelomorph
@SlavaKnyazev: This has been done, and the migrations are truly identical. Will post screenshots to show.Mattock
Isn't it odd to seed data in de Configure()?Celibate
You should be able to strip out everything except the modals and the dbcontext without much pain and post whatever is left. Having a reproducable example will do wonders for solving this. It may very well be that its a Microsoft bug, in which case doing it would be essential.Allelomorph
Can you state the version of entity framework being used?Gunflint
G
3

You seem to be using some EFC 3.1 version (up to 3.1.9 inclusive) which exhibits the bug #21661 - Using ValueGeneratedOnAdd on a property that is seeded causes UpdateData calls in every subsequent migration, fixed in 3.1.10+ by #22760 - [release/3.1] Fix issue where property with value generated on add is reseeded in every migration.

Note that every property having HasDefaultValue{Sql} like your IsSystemDefault is considered ValueGeneratedOnAdd by convention.

Now, to resolve the problem, either upgrade to EFC 3.10 or later, or use the following workaround with ValueGeneratedNever:

entityTypeBuilder
    .Property(thisTable => thisTable.IsSystemDefault)
    .HasDefaultValue(false)
    .ValueGeneratedNever(); // <-- add this
Genesisgenet answered 4/2, 2021 at 1:36 Comment(1)
Thank you very much! Adding the .ValueGeneratedNever() solved the problem. I will recommend to the team to update, though, as that seems like the better idea.Mattock

© 2022 - 2024 — McMap. All rights reserved.