实体类型的实例无法被跟踪,因为已经有另一个具有相同键值的实例正在被跟踪。

9

我从实体基类中得到了一个相同的键值运行时异常。我尝试了一些在线解决方案,但都没有成功。有谁能帮助我解决这个问题?在更新时,下面这行代码会抛出异常:

this.RepositoryContext.Set().Update(entity);

框架: .netcore 3.1

错误信息:

{"The instance of entity type 'JobConnection' cannot be tracked because another instance with the same key value for {'JobConnectionId'} 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."}.

此处为调用:

public void UpdateJobConn(JobConnection jobfile)
        {
            Update(jobfile);
            Save();
        }

这是整个仓库类(Repository class)的代码:

using Foreside.Etp.Contracts;
using Foreside.Etp.Entities.Models;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Linq;

namespace Foreside.Etp.Repository
{
    public abstract class RepositoryBase<T> : IRepositoryBase<T> where T : class
    {
        protected EtpRepoContext RepositoryContext { get; set; }

        public RepositoryBase(EtpRepoContext repositoryContext)
        {
            this.RepositoryContext = repositoryContext;
        }

        public IEnumerable<T> FindAll()
        {
            return this.RepositoryContext.Set<T>();
        }

        public IEnumerable<T> FindByCondition(Expression<Func<T, bool>> expression)
        {
            return this.RepositoryContext.Set<T>().Where(expression);
        }

        public void Create(T entity)
        {
            this.RepositoryContext.Set<T>().Add(entity);
        }

        public void Update(T entity)
        {
            this.RepositoryContext.Set<T>().Update(entity);
        }

        public void Delete(T entity)
        {
            this.RepositoryContext.Set<T>().Remove(entity);
        }

        public void Save()
        {
            this.RepositoryContext.SaveChanges();
        }
    }
}

JobConnection 模型 -

public partial class JobConnection
    {
        public int JobConnectionId { get; set; }
        public int KeyId { get; set; }
        public int ConnectionId { get; set; }
        public string Directory { get; set; }
        public int JobId { get; set; }
        public int ConnectiontypeId { get; set; }
    }

背景 -

 public virtual DbSet<JobConnection> JobConnection { get; set; }

modelBuilder.Entity<JobConnection>(entity =>
        {
            entity.ToTable("job_connection");

            entity.HasKey(e => e.JobConnectionId);

            entity.Property(e => e.JobConnectionId)
                .HasColumnName("jobconnectionid")
                .HasColumnType("int(11)");

            entity.Property(e => e.ConnectionId)
                .HasColumnName("connectionid")
                .HasColumnType("int(11)")
                .HasDefaultValueSql("0");

            entity.Property(e => e.ConnectiontypeId)
                .HasColumnName("connectiontypeid")
                .HasColumnType("int(11)");

            entity.Property(e => e.Directory)
                .IsRequired()
                .HasColumnName("directory")
                .HasMaxLength(50)
                .IsUnicode(false)
                .HasDefaultValueSql("0");

            entity.Property(e => e.JobId)
                .HasColumnName("jobid")
                .HasColumnType("int(11)");

            entity.Property(e => e.KeyId)
                .HasColumnName("keyid")
                .HasColumnType("int(11)")
                .HasDefaultValueSql("0");
        });

表格 -

SHOW INDEXES
FROM job_connection

job_connection  0   PRIMARY 1   jobconnectionid A   63              BTREE       

1
消息是不言自明的。您正在创建一个重复的键。 - T.S.
我知道它们很相似,但是我无法完全将那个解决方案适用于这里。我对 .netcore 不太熟悉。如果可以的话,你能否修改上面的代码呢?那会非常有帮助。 - Partha
在执行“update”操作之前,您可能需要在模型上设置新的“JobConnectionId”,该ID已被另一条记录使用。 - T.S.
好的。但是当我检查数据模型时,我发现JobConnectionId是主键,我们正在尝试更新数据库表中没有重复的记录。我们不会插入任何东西来复制它,而是更新一个在表中不存在的现有记录。因此,“提供的数据重复现有数据”的可能性不存在。您能否分享您的想法?有时候讨论可以帮助解决问题。 - Partha
显示剩余7条评论
2个回答

9

最后,我通过分离实体状态来解决了这个问题。非常感谢您分享您的想法——它有助于深入思考。请查看以下问题和正确的解决方案。

问题:

至少有一个孤儿跟踪实例阻止了我使用正确的实例更新数据库——基本上这是一个重复的实例,当上下文尝试在数据库中更新时会干扰,并且无法保存JobConnection的任何引用。上下文在离开声明和初始化范围后仍然在插入对象上存储引用。

解决方案:

有多种方法可以解决此问题。其中一种方法是从上下文中分离实例以避免类似的孤立重复实例,这是我们情况下导致问题的原因之一。以下是我如何在代码中修复的示例:

_context.Entry<JobConnection>(jobCon).State = EntityState.Detached;  //Explicitly Detach the orphan tracked instance 

以下是一段类似问题的代码示例以及解决方案。

var inFiles = _filerepository.FindAllInboundFilesByJobId(job.Jobid);
foreach (File inFile in inFiles)
_context.Entry<File>(inFile).State = EntityState.Detached;

1
似乎你没有使用类似于entity.HasKey(a => a.Id);这样的东西来指示主键,因此数据库行ID与您正在尝试更新的内存中的对象冲突。
在调用this.RepositoryContext.SaveChanges();之前,您应该调试并检查要更新的对象的ID。

谢谢,Guven。干得好。但是添加HasKey并不能解决问题。我已经添加了上下文部分,并尝试了修改后的代码。你能否请检查一下我是否犯了任何错误?谢谢。 - Partha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接