记录一次EF实体跟踪错误

这篇具有很好参考价值的文章主要介绍了记录一次EF实体跟踪错误。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

记录一次EF实体跟踪错误

前言

在我写文章编辑接口的,出现了一个实体跟踪的错误,详情如下

System.InvalidOperationException: The instance of entity type 'Tag' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.

System.InvalidOperationException:无法跟踪实体类型“Tag”的实例,因为已跟踪具有相同 {'Id'} 键值的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。考虑使用“DbContextOptionsBuilder.EnableSensitiveDataLogging”来查看冲突的键值。

代码

这是控制器,这个是用于修改文章的一个接口

[HttpPut("{id}")]
public async Task<ApiResponse<Post>> Update(string id, PostUpdateDto dto)
{
    var post = _postService.GetById(id);
    if (post == null) return ApiResponse.NotFound($"博客 {id} 不存在");
    
    post = _mapper.Map(dto, post);
    post.LastUpdateTime = DateTime.Now;
    return new ApiResponse<Post>(await _postService.InsertOrUpdateAsync(post));
}

PostUpdateDto类如下:

public class PostUpdateDto
    {
        public string Id { get; set; }
        /// <summary>
        /// 标题
        /// </summary>
        public string Title { get; set; }
        /// <summary>
        /// 梗概
        /// </summary>
        public string Summary { get; set; }
        /// <summary>
        /// 内容(markdown格式)
        /// </summary>
        public string Content { get; set; }
        /// <summary>
        /// 分类ID
        /// </summary>
        public int CategoryId { get; set; }
        /// <summary>
        /// 标签
        /// </summary>
        public List<Tag> Tags { get; set; }
    }

关键在于public List<Tag> Tags { get; set; } 这里,我使用了Map去让PostUpdateDto可以映射为post文章类,然后Tags是前端传过来的标签集合,同时也是post的导航属性,控制器是没毛病的,继续往下看。

然后是InsertOrUpdateAsync方法:

传递一个post实体对象,然后对实体进行增改操作,我按照常规的写法,修改标签,肯定是要将文章之前的标签删除掉,然后重新添加,这是正常的流程。PostTags就是标签表,用于维护标签和文章的关系,删除文章标签实际就是删除PostTags表的内容。

可以看到我删除了existingTags查询出的对象,也就是删除当前文章下的标签。然后通过遍历前端传过来的tags对象新增新的书签,之后就是保存到数据库的操作了。流程是没有问题的,但是每次编辑就报Tags实体跟踪错误

public async Task<Post> InsertOrUpdateAsync(Post post)
        {
            using var transaction = await _myDbContext.Database.BeginTransactionAsync();

            try
            {
                // 是新文章的话,先保存到数据库
                if (await _myDbContext.posts.FindAsync(post.Id) == null)
                {
                    post.ViewCount = 0;
                    await _myDbContext.posts.AddAsync(post);
                    await _myDbContext.SaveChangesAsync();
                }

                var tags = post.Tags.ToList();
                // 移除原有的标签,没写引发异常
                // post.Tags.Clear();
                var existingTags = await _myDbContext.PostTags
                    .Where(pt => pt.PostId == post.Id)
                    .ToListAsync();

                _myDbContext.PostTags.RemoveRange(existingTags);
                //修改
                foreach (var tagName in tags)
                {
                    var postTag = new PostTag
                    {
                        PostId = post.Id,
                        TagId = tagName.Id,
                    };

                    _myDbContext.PostTags.Add(postTag);
                }

                // 保存更改到数据库
                await _myDbContext.SaveChangesAsync();

                // 检查文章中的外部图片,下载并进行替换
                post.Content = await MdExternalUrlDownloadAsync(post);

                // 修改文章时,将markdown中的图片地址替换成相对路径再保存
                post.Content = MdImageLinkConvert(post, false);

                // 更新文章
                _myDbContext.posts.Attach(post);
                _myDbContext.Entry(post).State = EntityState.Modified;
                await _myDbContext.SaveChangesAsync();

                // 提交事务
                await transaction.CommitAsync();

                return post;
            }

错误在开头就说了,无法跟踪实体类型“Tag”的实例,我琢磨的很久,我明明没有查询Tag,也没有删除Tag,我删除的是PostTags表,为什么会报这个错误。而且我是没有做外键约束的。

解决

找了很久,发现了一个致命的漏点,我传递的post对象是一个导航属性的Tags的,如图:

记录一次EF实体跟踪错误

可以看到Tags里面是有PostTags的,所以当我获取所有标签var tags = post.Tags.ToList();同时删除PostTags中的内容的时候_myDbContext.PostTags.RemoveRange(existingTags)然后通过循环 foreach (var tagName in tags) 添加了新的标签,但是我并没有将这些标签从 post.Tags 集合中移除。因此,当我保存更改到数据库时,EF Core 会认为 post.Tags 集合中的标签实例已经被跟踪,导致了异常。

简单来说就是post中的Tags要被清除才行,也就是这行代码必须要写上去

// 移除原有的标签
post.Tags.Clear();

结论

当对具有导航属性的数据进行增删改的时候,先看看实体中是否存在这些数据,记得先Clear再执行操作。在Clear之前可以将需要的数据保存到变量中,因为Clear之后,是无法通过实体.(点)出属性了文章来源地址https://www.toymoban.com/news/detail-666356.html

到了这里,关于记录一次EF实体跟踪错误的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 记录一次错误的使用当前时间new Date()引发的错误

    前言    当我回顾自己的博客写作经历时,发现已经好久没有动笔了。然而,我深知互联网的强大之处,它让我们每个人都能轻松地获取信息和解决问题。每当我遇到困难时,只需上网搜索一番,往往就能找到答案。          这一切都得益于那些乐于分享经验和知识的人们

    2024年03月28日
    浏览(96)
  • Ef Core花里胡哨系列(5) 动态修改追踪的实体、动态查询

    同样还是 IModelCacheKeyFactory ,不过这次要采用主动刷新的方式。 动态实体,根据配置等生成动态类型来当作数据库实体使用,当配置修改时,可以调用 DynamicModelCacheKeyFactory.Refresh() 刷新DbContext。 动态构建部分不提供,我们将在其它的地方进行讨论。 我这里做了简化处理,直

    2024年02月03日
    浏览(38)
  • 使用EF6(DB First模式)无法生成对应模型实体类

    最近升级了,Visual Stidio 2022,在使用EF6时(DB First模式),无法生成对应模型的实体类,如下:  对于该问题,我去微软社区,找到了两个解决方案: 1.从 Visual Studio2022 16.x 版本回滚到 Visual Studio2022 15.x 版本即可解决问题; 2.修改EF6的实用程序.CS.ttinclude,它默认的位置在:C:Program FilesMicro

    2024年02月11日
    浏览(34)
  • .net 6 EF Core MySql数据库表生成实体类命令

    安装下面这几个包 Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore.Tools Microsoft.EntityFrameworkCore.Design Pomelo.EntityFrameworkCore.MySql Scaffold-DbContext “server=127.0.0.1;port=3306;database=DB;uid=root;pwd=pwdpwd;sslmode=none;” Pomelo.EntityFrameworkCore.MySql -OutputDir Models -Force -NoOnConfiguring -NoPluralize -Context “D

    2024年02月05日
    浏览(46)
  • .NET6.0 EF Core 之 DB First生成实体类

    EF Core可以使用DB First模式生成实体类具体步骤如下: 因为.NET Core中默认不包含EF Core的工具和程序包,需要通过NuGet管理器安装对应的工具和程序包,这里使用SQL Server数据库。 Microsoft.EntityFrameworkCore.SqlServer:SQL Server数据库EF提供程序 Microsoft.EntityFrameworkCore.Design:设计时使用到

    2024年02月06日
    浏览(50)
  • .NET6 + EF Core + MySQL 创建实体和数据库、EFCore 数据迁移

    接上期文章《.NET6项目连接数据库方式方法》,有人问了我几个问题,现在就这几个问题,拓展延申一下创建实体类、数据库。把ORM框架和数据迁移都写进去。 我的项目是在Linux上创建的,使用的是vscode开发工具远程开发。为了方便大家阅读和操作,我将项目down到我的本地电

    2024年02月05日
    浏览(51)
  • 关于VS2022使用EF生成实体模型报错的问题:运行转换:System.NullReferenceException:对象引用未设置为对象的示例。

    起因: 之前版本vs2022生成EF模型一直没有问题,在更新了最新的vs2022之后,版本号17.6+,出现此问题: 正在运行转换:System.NullReferenceException:未将对象引用设置到对象的实例。 具体错误如下: 正在运行转换: System.NullReferenceException: 未将对象引用设置到对象的实例。 在 Micro

    2024年02月08日
    浏览(52)
  • 记录一次浏览器HTTPS“你的连接不是私密连接”错误NET::ERR_CERT_REVOKED

    你的连接不是私密连接 NET::ERR_CERT_REVOKED CERT就是正式,意思就是证书错误 看到错误后,我们知道是https SLA认证的证书错误,所以我们先查看证书。 在浏览器的地址栏,左边点击红色的“不安全” 然后点击第一行的“连接”选项,看到右上角有证书按钮,点击这个按钮。 将会

    2024年02月07日
    浏览(54)
  • 记录一次老服务器启动ActiveMq时报的Could not create the Java Virtual Machine.错误

    服务器系统CentOS7  1、出现ActiveMq服务无法连接 2、查看activemq状态 service activemq status 显示activemq not running 3、找到ActiveMq的bin目录,# 后台启动 ./activemq console 提示Could not create the Java Virtual Machine.错误 可以判断是java运行环境的问题 4、再看看java版本 java -version 5、再看看activemq版

    2024年04月22日
    浏览(59)
  • 记录EF 排序配上自定义的比较器

    要求页面文件显示的时候能够按照序号去排序要求如下: 数据库有一个列存放文件名,如: 1.1文件 1.2文件 1.1.1文件 1.1.11文件1.0.txt 1.1.2(文件).pdf 现在需要实现查询的时候按照这个列排序,并且是按照序号排序。 查询的时候是按层级查询的,每次查询只会当前所在层,1

    2024年02月08日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包