VS2022迁移后EF 6.4.4出现ConceptualModels标签不匹配问题求助
问题描述
从Visual Studio 2017迁移到Visual Studio 2022时,先遇到Entity Framework错误“Value cannot be null. Parameter name: type”,于是将Entity Framework 6.2.0升级至6.4.4。执行数据库更新操作时,出现XML标签不匹配错误:第4行第6位的ConceptualModels起始标签与第1747行第7位的ConceptualModessociationSet结束标签不匹配。项目采用CodeFirst模式。
错误堆栈信息:
at System.Xml.XmlTextReaderImpl.ParseElementContent() at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r) at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r, LoadOptions o) at System.Xml.Linq.XDocument.Load(XmlReader reader, LoadOptions options) at System.Xml.Linq.XDocument.Load(Stream stream, LoadOptions options) at System.Data.Entity.Migrations.Edm.ModelCompressor.Decompress(Byte[] bytes) at System.Data.Entity.Migrations.DbMigration.GetModel(Func`2 modelAccessor) at System.Data.Entity.Migrations.DbMigrator.ApplyMigration(DbMigration migration, DbMigration lastMigration) at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ApplyMigration(DbMigration migration, DbMigration lastMigration) at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId) at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId) at System.Data.Entity.Migrations.DbMigrator.UpdateInternal(String targetMigration) at System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase) at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration) at System.Data.Entity.Infrastructure.Design.Executor.Update.<>c__DisplayClass0_0.<.ctor>b__0() at System.Data.Entity.Infrastructure.Design.Executor.OperationBase.Execute(Action action) The 'ConceptualModels' start tag on line 4 position 6 does not match the end tag of 'ConceptualModessociationSet'. Line 1747, position 7.
DBContext代码:
namespace GMM.Repository.Context { public class GMMDbContext : IdentityDbContext<ApplicationUser, AppRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim> { public static string ConnectionString { get; set; } static GMMDbContext() { #if DEBUG ConnectionString = "GMMConnection"; #endif } public static GMMDbContext Create() { return new GMMDbContext(); } public GMMDbContext() : base(ConnectionString) { Database.SetInitializer(new MigrateDatabaseToLatestVersion<GMMDbContext, GMM.Repository.Migrations.Configuration>()); DbInterception.Add(new FtsInterceptor()); } #region AccessControl public IDbSet<GroupRole> GroupRoles { get; set; } public IDbSet<RoleGroup> RoleGroups { get; set; } public IDbSet<UserRoleGroup> UserRoleGroups { get; set; } #endregion #region BaseInformation public IDbSet<Department> Departments { get; set; } #endregion #region General public IDbSet<Location> Locations { get; set; } public IDbSet<Setting> Settings { get; set; } #endregion public int SaveChanges(string currentUserIp) { AddTimestamps(currentUserIp); return base.SaveChanges(); } public Task<int> SaveChangesAsync(string userIp) { AddTimestamps(userIp); return base.SaveChangesAsync(); } public override int SaveChanges() { AddTimestamps(); return base.SaveChanges(); } private void AddTimestamps(string currentUserId, string currentUserIp) { if (currentUserId == null) { throw new NullReferenceException("CurrentUserId"); } var entities = ChangeTracker.Entries().Where(x => x.Entity is IBaseEntity && (x.State == EntityState.Added || x.State == EntityState.Modified)); foreach (var entity in entities) { if (entity.State == EntityState.Added) { ((BaseGuidEntity)entity.Entity).DateCreated = DateTime.Now; ((BaseGuidEntity)entity.Entity).CreatedBy_Id = currentUserId; ((BaseGuidEntity)entity.Entity).CreatedByIp = currentUserIp; } ((BaseGuidEntity)entity.Entity).DateModified = DateTime.Now; ((BaseGuidEntity)entity.Entity).ModifiedBy_Id = currentUserId; ((BaseGuidEntity)entity.Entity).ModifiedByIp = currentUserIp; } } private void AddTimestamps() { var entities = ChangeTracker.Entries().Where(x => x.Entity is IBaseEntity && (x.State == EntityState.Added || x.State == EntityState.Modified)); foreach (var entity in entities) { if (entity.State == EntityState.Added) { ((BaseGuidEntity)entity.Entity).DateCreated = DateTime.UtcNow; } ((BaseGuidEntity)entity.Entity).DateModified = DateTime.UtcNow; } } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); #region Message modelBuilder.Configurations.Add(new PrivacyConfig()); modelBuilder.Configurations.Add(new ResultConfig()); modelBuilder.Configurations.Add(new SubjectConfig()); modelBuilder.Configurations.Add(new PriorityConfig()); modelBuilder.Configurations.Add(new CategoryConfig()); modelBuilder.Configurations.Add(new MessageConfig()); modelBuilder.Configurations.Add(new MessageFeedbackConfig()); modelBuilder.Configurations.Add(new ReferConfig()); #endregion base.OnModelCreating(modelBuilder); } } }
模型图:
解决方案
修复迁移历史表中的损坏XML
- 连接目标数据库,找到
__MigrationHistory表,定位对应迁移记录的Model字段(该字段为二进制存储的压缩XML)。 - 编写工具代码解压二进制数据:
using System.Data.Entity.Migrations.Edm; using System.IO; using System.Xml.Linq; // 从数据库读取到的Model字段字节数组 byte[] modelBytes = /* 读取数据库中的二进制数据 */; var decompressedData = ModelCompressor.Decompress(modelBytes); using (var ms = new MemoryStream(decompressedData)) { var modelXml = XDocument.Load(ms); modelXml.Save("model.xml"); // 保存到本地文件查看 } - 打开
model.xml文件,定位到第1747行,将错误的结束标签</ConceptualModessociationSet>修正为</ConceptualModels>(该错误是标签拼接失误,将ConceptualModels与AssociationSet错误合并)。 - 将修正后的XML重新压缩,更新回
__MigrationHistory表的对应记录:var correctedXml = XDocument.Load("corrected_model.xml"); using (var ms = new MemoryStream()) { correctedXml.Save(ms); ms.Position = 0; byte[] compressedBytes = ModelCompressor.Compress(ms.ToArray()); // 将compressedBytes更新到数据库的Model字段 }
- 连接目标数据库,找到
检查模型配置是否存在错误
- 查看
OnModelCreating方法中添加的各类实体配置类(如PrivacyConfig、MessageConfig等),排查以下问题:- 重复定义的导航属性
- 错误的外键关联设置
- 多对多关系配置失误
- 对照模型图,确认所有实体间的关联关系是否正确,避免因模型结构问题导致生成的ConceptualModels XML异常。
- 查看
重置迁移(备选方案,需谨慎操作)
若迁移历史损坏严重无法单独修复,可尝试重置迁移流程:- 备份当前数据库,避免数据丢失。
- 删除项目中
Migrations文件夹下的所有迁移文件。 - 删除数据库中的
__MigrationHistory表。 - 在Package Manager Console中执行以下命令:
Enable-Migrations -Force Add-Migration Initial Update-Database -Script - 对比生成的SQL脚本与现有数据库结构,调整后再执行脚本,确保数据不会被覆盖。
内容的提问来源于stack exchange,提问作者MR Alam
相关产品推荐
相关产品推荐

