我目前正在尝试使用实体框架移动 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),它确实有效。但是我不允许更改数据,因此这不是有效的解决方案。
实体框架的默认行为是考虑像 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。分离这里的实体没有帮助。