我有一个数据库,需要在两个现有表之间引入新的必需 FK 关系。由于它们都有现有数据(并且产品已经在生产中运行),因此我需要采取更多步骤来添加新列和 FK 关系。
第一次迁移向现有表添加了一个新的、可为空的
Guid
列,该列将成为 FK 关系中的主要列。然后,我使用自定义 SQL 脚本使用另一个表中的相应值更新了表中的记录。
然后,我更新了模型,使相同的 Guid
不可为空,并生成了新的迁移,这还向列添加了索引。
到这里一切都很好。
然后,我在两个模型的配置中配置了 FK 关系并生成了新的迁移。然而,这种迁移似乎拒绝接受模型和配置的更改。
以下是模型定义和相应的配置。
感兴趣的属性与
Registry
有关。public class Company
{
/// <summary>
/// Gets or sets the unique identifier of the <see cref="Company"/>.
/// </summary>
public Guid Id { get; set; } = Guid.NewGuid();
/// <summary>
/// Gets or sets the name of the <see cref="Company"/>.
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the unique identifier of the <see cref="Group"/> to which the <see cref="Company"/> belongs.
/// </summary>
public Guid? GroupId { get; set; }
/// <summary>
/// Gets or sets the unique identifier of the <see cref="Registry"/> from which the <see cref="Company"/> entity was created.
/// </summary>
public Guid RegistryId { get; set; }
/// <summary>
/// Gets the date and time at which the <see cref="Company"/> was created.
/// </summary>
public DateTime CreatedAt { get; } = DateTime.UtcNow;
/// <summary>
/// Gets or sets the unique identifier of the user who created the <see cref="Company"/>.
/// </summary>
public Guid CreatedBy { get; set; } = Guid.Empty;
/// <summary>
/// Gets or sets the date and time at which the <see cref="Company"/> was last updated.
/// </summary>
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
/// <summary>
/// Gets or sets a concurrency token used to prevent conflicting edits in a <see cref="Company"/> entity.
/// </summary>
[SuppressMessage("ReSharper", "PropertyCanBeMadeInitOnly.Global", Justification = "Used by Entity Framework.")]
public byte[] RowVersion { get; set; } = null!;
/// <summary>
/// Gets or sets the <see cref="Group"/> to which the <see cref="Company"/> is linked through <see cref="GroupId"/>.
/// </summary>
public Group? Group { get; set; }
/// <summary>
/// Gets or sets the <see cref="Registry"/> to which the <see cref="Company"/> is linked through <see cref="RegistryId"/>.
/// </summary>
public Registry Registry { get; set; } = null!;
/// <summary>
/// Gets or sets a collection of <see cref="SystemIdentifier"/> linked to this <see cref="Company"/>.
/// </summary>
public ICollection<SystemIdentifier> SystemIdentifiers { get; set; } = null!;
/// <summary>
/// Gets or sets a collection of <see cref="User"/> linked to this <see cref="Company"/>.
/// </summary>
public ICollection<User> Users { get; set; } = null!;
/// <summary>
/// Gets or sets a collection of <see cref="Permission"/> linked to this <see cref="Company"/>.
/// </summary>
public ICollection<Permission> Permissions { get; set; } = null!;
}
注册表
public class Registry
{
/// <summary>
/// Gets or sets the unique identifier of the <see cref="Registry"/>.
/// </summary>
public Guid Id { get; set; } = Guid.NewGuid();
/// <summary>
/// Gets or sets a token required to verify the <see cref="Registry"/>.
/// </summary>
public string? RegistrationToken { get; set; }
/// <summary>
/// Gets or sets the name of the company to which the registered client belongs.
/// </summary>
public string? CompanyName { get; set; }
/// <summary>
/// Gets or sets a JSON string containing a list of requested users.
/// </summary>
public string? RequestedUsers { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the specified user in the registry are handled.
/// </summary>
public bool IsHandled { get; set; }
/// <summary>
/// Gets or sets a concurrency token used to prevent conflicting edits to a <see cref="Registry"/> entity.
/// </summary>
public byte[] RowVersion { get; set; } = null!;
/// <summary>
/// Gets or sets the date and time at which the <see cref="Registry"/> was created.
/// </summary>
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
/// <summary>
/// Gets or sets the date and time at which the <see cref="Registry"/> was last updated.
/// </summary>
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
/// <summary>
/// Gets or sets a collection of <see cref="RegistryAgreement"/> entities linked to the <see cref="Registry"/>.
/// </summary>
public ICollection<RegistryAgreement> Agreements { get; set; } = null!;
/// <summary>
/// Gets or sets a collection fo <see cref="Company"/> entities linked to the <see cref="Registry"/>.
/// </summary>
public ICollection<Company> Companies { get; set; } = null!;
}
公司配置
public class CompanyConfiguration : IEntityTypeConfiguration<Company>
{
/// <inheritdoc />
public void Configure(EntityTypeBuilder<Company> builder)
{
builder = builder ?? throw new ArgumentNullException(nameof(builder));
builder.HasKey(c => c.Id);
builder.Property(c => c.Id)
.HasDefaultValueSql("NEWID()");
builder.Property(c => c.Name)
.IsRequired()
.HasMaxLength(75);
builder.Property(c => c.RegistryId)
.IsRequired();
builder.Property(c => c.CreatedAt)
.HasDefaultValueSql("getdate()")
.ValueGeneratedOnAdd()
.IsRequired();
builder.Property(c => c.CreatedBy)
.IsRequired();
builder.Property(c => c.UpdatedAt)
.HasDefaultValueSql("getdate()")
.ValueGeneratedOnAddOrUpdate()
.IsRequired();
builder.Property(c => c.RowVersion)
.IsRowVersion();
builder.HasOne(c => c.Group)
.WithMany(g => g.Companies)
.HasForeignKey(c => c.GroupId)
.OnDelete(DeleteBehavior.SetNull)
.IsRequired(false);
builder.HasOne(c => c.Registry)
.WithMany(r => r.Companies)
.HasForeignKey(c => c.RegistryId)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
builder.HasMany(c => c.Permissions)
.WithOne(p => p.Company)
.HasForeignKey(p => p.CompanyId)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired(false);
builder.HasMany(c => c.SystemIdentifiers)
.WithOne(si => si.Company)
.HasForeignKey(si => si.CompanyId)
.OnDelete(DeleteBehavior.NoAction)
.IsRequired(false);
}
}
注册表
public class RegistryConfiguration : IEntityTypeConfiguration<Registry>
{
/// <inheritdoc />
public void Configure(EntityTypeBuilder<Registry> builder)
{
builder = builder ?? throw new ArgumentNullException(nameof(builder));
builder.HasKey(r => r.Id);
builder.Property(r => r.Id)
.HasDefaultValueSql("NEWID()")
.ValueGeneratedOnAdd()
.IsRequired();
builder.Property(r => r.IsHandled)
.ValueGeneratedOnAdd()
.HasDefaultValueSql("0")
.HasColumnType("bit")
.IsRequired();
builder.Property(r => r.CreatedAt)
.HasDefaultValueSql("getdate()")
.ValueGeneratedOnAdd()
.IsRequired();
builder.Property(r => r.UpdatedAt)
.HasDefaultValueSql("getdate()")
.ValueGeneratedOnAddOrUpdate()
.IsRequired();
builder.Property(r => r.RowVersion)
.IsRowVersion();
builder.HasMany(r => r.Agreements)
.WithOne(ra => ra.Registry)
.HasForeignKey(ra => ra.RegistryId)
.OnDelete(DeleteBehavior.NoAction);
builder.HasMany(r => r.Companies)
.WithOne(c => c.Registry)
.HasForeignKey(c => c.RegistryId)
.OnDelete(DeleteBehavior.NoAction);
}
}
我在 StackOverflow 上针对其他类似问题尝试了一些发布的解决方案,但似乎都不起作用。这是我尝试过的:
Update-Database
,然后删除并覆盖最后一个迁移。
Update-Database
,删除最后一个迁移,删除快照中的更改,然后创建新迁移。
我意识到这个问题已经发布了好几次,所以如果这里还有另一个问题有正确的答案,请随时将其标记为可能重复!
提前致谢!
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
new CompanyConfiguration().Configure(modelBuilder.Entity<Company>());
new RegistryConfiguration().Configure(modelBuilder.Entity<Registry>());
base.OnModelCreating(modelBuilder);
}