-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Entity Framework Core 7 keeps creating the same migration for Nullable DateTime field #29985
Comments
@ruban211097 I am not able to reproduce this--see my code below. Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate. public class SomeDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(@"Data Source=(LocalDb)\MSSQLLocalDB;Database=AllTogetherNow")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var defaultPolicy = new MatchingPolicy()
{
Id = Guid.Parse("5cf3f8e5-50e1-47c8-aa42-40b1824ea099"),
CompanyId = null,
Name = "PASA data Matching convention (DMC)",
Status = MatchingPolicyStatus.Draft,
Type = MatchingPolicyType.Default,
Description = "Bla bla.",
CreatedDate = new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc).AddTicks(1258),
};
var defaultPolicyVersion = new MatchingPolicyVersion()
{
Id = Guid.Parse("5cf3f8e5-50e1-47c8-aa42-40b1824ea098"),
CreatedByUserName = "System",
MatchingPolicyId = defaultPolicy.Id,
ReviewerUserName = "System",
Status = MatchingPolicyApprovalStatus.Approved,
Version = 1,
CreatedDate = new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc),
UpdatedDate = new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc),
};
var defaultGroups = new[]
{
new MatchingPolicyGroup
{
Id = Guid.Parse("1e93b3f9-4ed8-4b90-a859-31b6503ec89f"),
MatchingPolicyVersionId = defaultPolicyVersion.Id,
Group = MatchingPolicyGroupType.Full,
CreatedDate = new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc).AddTicks(1258),
},
new MatchingPolicyGroup
{
Id = Guid.Parse("b08f004f-a62d-409e-8025-337f0eb73054"),
MatchingPolicyVersionId = defaultPolicyVersion.Id,
Group = MatchingPolicyGroupType.Possible,
CreatedDate = new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc).AddTicks(1258),
},
};
modelBuilder.Entity<MatchingPolicy>().HasData(defaultPolicy);
modelBuilder.Entity<MatchingPolicyVersion>().HasData(defaultPolicyVersion);
modelBuilder.Entity<MatchingPolicyGroup>().HasData(defaultGroups);
modelBuilder.Entity<Scheme>().Property(u => u.MatchingPolicyId).HasDefaultValue(defaultPolicy.Id);
}
}
public class Scheme
{
public Guid Id { get; set; }
public Guid? MatchingPolicyId { get; set; }
}
public enum MatchingPolicyGroupType
{
Full,
Possible
}
public class MatchingPolicyGroup
{
public Guid Id { get; set; }
public Guid MatchingPolicyVersionId { get; set; }
public MatchingPolicyGroupType Group { get; set; }
public DateTime? CreatedDate { get; set; }
}
public class MatchingPolicyVersion
{
public Guid Id { get; set; }
public MatchingPolicyApprovalStatus Status { get; set; }
public DateTime CreatedDate { get; set; }
public string CreatedByUserName { get; set; }
public Guid MatchingPolicyId { get; set; }
public string ReviewerUserName { get; set; }
public int Version { get; set; }
public DateTime? UpdatedDate { get; set; }
}
public enum MatchingPolicyApprovalStatus
{
Approved
}
public enum MatchingPolicyType
{
Default
}
public enum MatchingPolicyStatus
{
Draft
}
public class MatchingPolicy
{
public Guid Id { get; set; }
public Guid? CompanyId { get; set; }
public string Name { get; set; }
public MatchingPolicyStatus Status { get; set; }
public MatchingPolicyType Type { get; set; }
public string Description { get; set; }
public DateTime? CreatedDate { get; set; }
}
public class Program
{
public static async Task Main()
{
using (var context = new SomeDbContext())
{
}
}
} First migration: using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
namespace Migrations
{
/// <inheritdoc />
public partial class One : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "MatchingPolicy",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
CompanyId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Name = table.Column<string>(type: "nvarchar(max)", nullable: false),
Status = table.Column<int>(type: "int", nullable: false),
Type = table.Column<int>(type: "int", nullable: false),
Description = table.Column<string>(type: "nvarchar(max)", nullable: false),
CreatedDate = table.Column<DateTime>(type: "datetime2", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_MatchingPolicy", x => x.Id);
});
migrationBuilder.CreateTable(
name: "MatchingPolicyGroup",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
MatchingPolicyVersionId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Group = table.Column<int>(type: "int", nullable: false),
CreatedDate = table.Column<DateTime>(type: "datetime2", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_MatchingPolicyGroup", x => x.Id);
});
migrationBuilder.CreateTable(
name: "MatchingPolicyVersion",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Status = table.Column<int>(type: "int", nullable: false),
CreatedDate = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatedByUserName = table.Column<string>(type: "nvarchar(max)", nullable: false),
MatchingPolicyId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ReviewerUserName = table.Column<string>(type: "nvarchar(max)", nullable: false),
Version = table.Column<int>(type: "int", nullable: false),
UpdatedDate = table.Column<DateTime>(type: "datetime2", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_MatchingPolicyVersion", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Scheme",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
MatchingPolicyId = table.Column<Guid>(type: "uniqueidentifier", nullable: true, defaultValue: new Guid("5cf3f8e5-50e1-47c8-aa42-40b1824ea099"))
},
constraints: table =>
{
table.PrimaryKey("PK_Scheme", x => x.Id);
});
migrationBuilder.InsertData(
table: "MatchingPolicy",
columns: new[] { "Id", "CompanyId", "CreatedDate", "Description", "Name", "Status", "Type" },
values: new object[] { new Guid("5cf3f8e5-50e1-47c8-aa42-40b1824ea099"), null, new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc).AddTicks(1258), "Bla bla.", "PASA data Matching convention (DMC)", 0, 0 });
migrationBuilder.InsertData(
table: "MatchingPolicyGroup",
columns: new[] { "Id", "CreatedDate", "Group", "MatchingPolicyVersionId" },
values: new object[,]
{
{ new Guid("1e93b3f9-4ed8-4b90-a859-31b6503ec89f"), new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc).AddTicks(1258), 0, new Guid("5cf3f8e5-50e1-47c8-aa42-40b1824ea098") },
{ new Guid("b08f004f-a62d-409e-8025-337f0eb73054"), new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc).AddTicks(1258), 1, new Guid("5cf3f8e5-50e1-47c8-aa42-40b1824ea098") }
});
migrationBuilder.InsertData(
table: "MatchingPolicyVersion",
columns: new[] { "Id", "CreatedByUserName", "CreatedDate", "MatchingPolicyId", "ReviewerUserName", "Status", "UpdatedDate", "Version" },
values: new object[] { new Guid("5cf3f8e5-50e1-47c8-aa42-40b1824ea098"), "System", new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc), new Guid("5cf3f8e5-50e1-47c8-aa42-40b1824ea099"), "System", 0, new DateTime(2022, 8, 11, 11, 35, 8, 586, DateTimeKind.Utc), 1 });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "MatchingPolicy");
migrationBuilder.DropTable(
name: "MatchingPolicyGroup");
migrationBuilder.DropTable(
name: "MatchingPolicyVersion");
migrationBuilder.DropTable(
name: "Scheme");
}
}
} Second migration: using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Migrations
{
/// <inheritdoc />
public partial class Two : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
} |
I can confirm this behavior using version 7.0.2 against a SQL server database. On every migration my nullable datetime fields are updated. My configuration looks as follows: b.Property(p => p.RevokedOn)
.HasConversion(
p => p,
p => p != null ? DateTime.SpecifyKind(p.Value, DateTimeKind.Utc) : null);
builder.HasData(new
{
ApiKey = Guid.Parse("9ebcb03af21e43a1af2a036871cc59f5"),
AccountId = Guid.Parse("9e3bbf26bcb346758648f7d18906a138"),
CreatedOn = new DateTime(2023, 1, 1, 0, 0, 0, DateTimeKind.Utc),
Comment = "Initial creation",
IsRevoked = false,
}); And every time I create a new migration the public partial class Test : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.UpdateData(
table: "AccountApiKeys",
keyColumns: new[] { "AccountId", "ApiKey" },
keyValues: new object[] { new Guid("9ebcb03af21e43a1af2a036871cc59f5"), new Guid("9e3bbf26bcb346758648f7d18906a138") },
column: "RevokedOn",
value: null);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.UpdateData(
table: "AccountApiKeys",
keyColumns: new[] { "AccountId", "ApiKey" },
keyValues: new object[] { new Guid("9ebcb03af21e43a1af2a036871cc59f5"), new Guid("9e3bbf26bcb346758648f7d18906a138") },
column: "RevokedOn",
value: null);
}
} I've tried explicitly adding |
Note for triage: I was able to repro this on 7.0.2, but it does not repro with the 8.0 daily build. However, I'm not sure which issue has the same root cause. public class Program
{
public static async Task Main()
{
using (var context = new SomeDbContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
}
}
}
public class Account
{
public Guid AccountId { get; set; }
public Guid ApiKey { get; set; }
public DateTime? RevokedOn { get; set; }
public DateTime CreatedOn { get; set; }
public string? Comment { get; set; }
public bool IsRevoked { get; set; }
}
public class SomeDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Data Source=(LocalDb)\MSSQLLocalDB;Database=AllTogetherNow")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Account>(
b =>
{
b.Property(p => p.RevokedOn)
.HasConversion(
p => p,
p => p != null ? DateTime.SpecifyKind(p.Value, DateTimeKind.Utc) : null);
b.HasData(new
{
ApiKey = Guid.Parse("9ebcb03af21e43a1af2a036871cc59f5"),
AccountId = Guid.Parse("9e3bbf26bcb346758648f7d18906a138"),
CreatedOn = new DateTime(2023, 1, 1, 0, 0, 0, DateTimeKind.Utc),
Comment = "Initial creation",
IsRevoked = false,
});
});
}
} |
@dotnet/efteam So, this is fixed in 8.0, but not in 7.0.3. I cannot find which change fixed this, but I think we need to do so, since we have had multiple reports and I think we need to consider servicing. Anybody remember changing anything that might have fixed this? |
Poaching |
Have entities with nullable DateTime inside called "UpdatedDate".
And when I'm trying add data to db by using HasData, `
It always creates the same migration with updating "UpdatedDate" field, even if this migration exist
The text was updated successfully, but these errors were encountered: