尝试使用实体框架持久保存到空 MySQL 数据库时出现重复键错误

问题描述 投票:0回答:1

我目前正在尝试使用实体框架移动 MySQL 数据库。 首先,我选择一个只有 8 行的小表,但是当我将它们添加到我的

DbContext
并保存时,会出现错误,提示存在重复键违规。

我检查了条目,它们都有唯一的 ID(0-7)。

这是我的代码:

static void Main(string[] args)
{
    CreateDb();
    LoadIndustryGroups();
}

static void LoadIndustryGroups()
{
    var result = RemoteController.OpenDatabase();
    var ig = RemoteController.GetAllIndustryGroups().Result;

    foreach (var group in ig)
    {
        Console.WriteLine($"{group.industrygroupID} {group.Description} {group.Notes}");
    }

    using (var context = new J1939DbContext())
    {
        context.Database.EnsureCreated();

        foreach (var group in ig)
        {
            context.Entry(group).State = EntityState.Detached;
        }

        context.IndustryGroups.AddRange(ig);

        try
        {
            context.SaveChanges();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
    }
}

这就是我的

DbContext
的样子:

public class J1939DbContext : DbContext
{
    static readonly string connectionString = "Server=localhost; User ID=x; Password=x; Database=test_db; Port=3307";

    public DbSet<IndustryGroup> IndustryGroups { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
        optionsBuilder.EnableSensitiveDataLogging(true);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<IndustryGroup>(entity =>
        {
            entity.HasKey(e => e.industrygroupID);
            entity.Property(e => e.Notes);
            entity.Property(e => e.Description);
            entity.Property(e => e.Revised);
        });
     }
}

错误信息是:

Microsoft.EntityFrameworkCore.DbUpdateException:保存实体更改时发生错误。有关详细信息,请参阅内部异常。

System.InvalidOperationException:无法跟踪实体类型“IndustryGroup”的实例,因为已跟踪具有键值“{industrygroupID:2}”的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.ThrowIdentityConflict(InternalEntityEntry entry)  
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)  
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.KeyPropertyChanged(InternalEntityEntry entry, IProperty property, IEnumerable`1 containingPrincipalKeys, IEnumerable`1 containingForeignKeys, Object oldValue, Object newValue)    
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectKeyChange(InternalEntityEntry entry, IProperty property)  
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.PropertyChanged(InternalEntityEntry entry, IPropertyBase propertyBase, Boolean setModified)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetProperty(IPropertyBase propertyBase, Object value, Boolean isMaterialization, Boolean setModified, Boolean isCascadeDelete, CurrentValueType valueType)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetStoreGeneratedValue(IProperty property, Object value, Boolean setModified)
at Microsoft.EntityFrameworkCore.Update.ColumnModification.set_Value(Object value)
at Pomelo.EntityFrameworkCore.MySql.Update.Internal.MySqlModificationCommand.PropagateResults(RelationalDataReader relationalReader)
at Pomelo.EntityFrameworkCore.MySql.Update.Internal.MySqlModificationCommandBatch.ConsumeResultSet(Int32 startCommandIndex, RelationalDataReader reader)
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.Consume(RelationalDataReader reader)
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.Consume(RelationalDataReader reader)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IList`1 entriesToSave)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(StateManager stateManager, Boolean acceptAllChangesOnSuccess)
at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
at EfTest.Program.LoadIndustryGroups() in E:\J1939_DB\Source\EfTest\Program.cs:line 43

这是旧数据库中的表的样子,我检查它们是否已正确加载:

我尝试给他们不同的ID(旧ID + 1000),它确实有效。但是我不允许更改数据,因此这不是有效的解决方案。

c# entity-framework
1个回答
0
投票

实体框架的默认行为是考虑像 IDENTITY(自动增量列)这样的 INT 类型属性,其名称以“Id”结尾,因此我们假设您已禁用它(例如在 SQL 上发出“SET IDENTITY_INSERT ON”)桌子)。现在您想要插入 8 行,其中 industrygroupID已设置。假设,可能在第一次之后,每次运行代码时,无需先清除实体框架数据库,您尝试再次插入相同范围的 8 行,其 IndustrygroupID 值(您也像 PK 一样定义)已经存在于EF db.

所以,首先要使用:

context.Database.EnsureDeleted();
context.Database.EnsureCreated();

删除并重新创建 EF 数据库。

并且,我认为正确的考虑是让 EF 管理自动增量 PK(industrygroupID)。因此,当您插入行时,它们的 industrygroupID 属性必须设置为 0

PS。分离这里的实体没有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.