无法跟踪实体类型“ TestType”的实例,因为已经跟踪了具有相同键的该类型的另一个实例 [英] The instance of entity type 'TestType' cannot be tracked because another instance of this type with the same key is already being tracked

查看:105
本文介绍了无法跟踪实体类型“ TestType”的实例,因为已经跟踪了具有相同键的该类型的另一个实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试执行以下操作时会遇到以下异常:

I am getting the below exception when I try to do:

    context.Entry(testType).State = EntityState.Modified;


System.InvalidOperationException: The instance of entity type 'TestType' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (i.e. if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context.
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges)
   at Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry.set_State(EntityState value)

我看不到已跟踪具有相同键的另一个TestType实例的任何代码!

I do not see any code where another TestType instance with a same key is already tracked!

数据库通过 .AsNoTracking();

加载在这段代码中,哪里有我具有RemoveRange / AddRange操作的具有相同键的TestType实例?

So where in this code are instances of TestType with the same key where I do an RemoveRange/AddRange operation on? That would mean that my TestTypeComparer is broken?

我在这里尝试做的是让用户批次一次保存已更改/添加/删除的实体:

What I try to do here is to let the user batch save changed/add/deleted entities in one go:

 public async Task<IEnumerable<TestType>> SaveTestTypesAsync(List<TestType> testTypes, int schoolyearId, int schoolclassId, int subjectId)
        {
            var testTypesFromDatabase = await context.TestTypes
                                          .Include(t => t.Subject)
                                          .Include(s => s.Schoolclass)
                                          .Where(p =>
                                          p.Schoolclass.Id == schoolclassId &&
                                          p.Subject.Id == subjectId)
                                          .AsNoTracking()
                                          .ToListAsync();

            var schoolclass = new Schoolclass { Id = schoolclassId };
            var subject = new Subject { Id = subjectId };
            var schoolyear = new Schoolyear { Id = schoolyearId };
            foreach (var testType in testTypes)
            {
                testType.Schoolclass = schoolclass;
                testType.Subject = subject;
                testType.Schoolyear = schoolyear;
            }

            var testTypesToRemove = testTypesFromDatabase.Except(testTypes, new TestTypeComparer()).ToList();
            context.TestTypes.RemoveRange(testTypesToRemove);

            var testTypesToAdd = testTypes.Where(t => t.Id == 0).ToList();  // 
            context.TestTypes.AddRange(testTypesToAdd);

            var modifiedTestTypesToUpdate = testTypes.Except(testTypesToAdd.Concat(testTypesToRemove).ToList(), new TestTypeComparer()).ToList();
            foreach (var testType in modifiedTestTypesToUpdate)
            {
                context.Entry(testType).State = EntityState.Modified;
            }

            context.Attach(schoolclass);      
            context.Attach(subject);
            context.Attach(schoolyear);

            await context.SaveChangesAsync();

            return await this.GetTestTypesConfigurationAsync(schoolclassId, subjectId);
        }


public class TestTypeComparer : IEqualityComparer<TestType>
{
    public bool Equals(TestType x, TestType y)
    {
        return x.Id == y.Id;
    }

    public int GetHashCode(TestType obj)
    {
        return obj.Id.GetHashCode();
    }
}

public class TestType
    {
        public TestType()
        {
            Tests = new HashSet<Test>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public int Weight { get; set; }
        public ISet<Test> Tests { get; set; }
        public Schoolyear Schoolyear { get; set; }  
        public Schoolclass Schoolclass { get; set; }
        public int SchoolclassId { get; set; }
        public Subject Subject { get; set; }
        public int SubjectId { get; set; }
        public int SchoolyearId { get; set; }
    }

任何人都可以帮助我,但我找不到双

我只是假设问题与确定我添加/修改/删除的实体有关。

更新

我现在已经记录了所有跟踪器更改我为所有TestTypesToUpdate设置了State.Modified:

I have now logged all the tracker changes just before I set the State.Modified for all TestTypesToUpdate:

State: Deleted | Type: TestType | Id-Value: 12
State: Unchanged | Type: Schoolclass | Id-Value: 1
State: Unchanged | Type: TestType | Id-Value: 8
State: Unchanged | Type: Subject | Id-Value: 1
State: Deleted | Type: TestType | Id-Value: 13
State: Added | Type: TestType | Id-Value: -2147482647
State: Detached | Type: Schoolclass | Id-Value: 1
State: Added | Type: Schoolyear | Id-Value: 1
State: Detached | Type: Subject | Id-Value: 1
State: Added | Type: TestType | Id-Value: -2147482646

似乎是的……某些实体已被跟踪。似乎我必须在变更跟踪器上进行其他投资,然后再决定要怎么做。

It seems yeah ... some entities are already tracked. Seems I have to invest some more if/else with the change tracker and then decide what to do.

但是我不敢相信我是第一个这样做的人,还没有在Google上找到任何东西。

But I can not believe that I am the first doing something like that, havent found anything on google.

推荐答案

考虑了多个具有相同键的实例问题后,我重新安排了工作再次输入代码,直到再次出现错误,我无法将testTypeToUpdate的状态设置为state。由于SchoolclassId是键的一部分,因此进行了修改。

After thinking about multiple instances with same key problem I rearranged the code a bit again until I got the error again, that I can not set the state of testTypeToUpdate to state.Modified because SchoolclassId is part of a key.

好。 ..然后我在流畅的迁移中进行搜索,发现了以下内容:

Well... then I searched in my fluent migrations and found this:

modelBuilder.Entity<TestType>().HasAlternateKey(x => new { x.Name, x.SchoolclassId, x.SubjectId });

我前阵子这样做(但从未测试过-对我感到羞耻-),我认为相当于索引属性的EF6 ...因为那就是我想要的功能!

I did this a while ago (but never tested it - shame on me -) and I thought its the EF6 equivalent to the Index Attribute... Because thats the feature I wanted!

然后我用Google搜索并创建了新的东西:

Then I googled and created something new:

modelBuilder.Entity<TestType>().HasIndex(p => new { p.Name, p.SchoolclassId, p.SubjectId} ).IsUnique();

现在我有了我想要的东西!

Now I have what I wanted!

我还删除了分配给testTypesToRemove的schoolclass,subject和schoolyear实例,这也创建了一些奇怪的东西...

I also removed the assigned of the schoolclass, subject and schoolyear instance to the testTypesToRemove that also created some weird stuff...

该代码现在可以正常工作:

That code works now:

   public async Task<IEnumerable<TestType>> SaveTestTypesAsync(List<TestType> testTypes, int schoolyearId, int schoolclassId, int subjectId)
        {
            var testTypesFromDatabase = await context.TestTypes
                                          .Include(t => t.Subject)
                                          .Include(s => s.Schoolclass)
                                          .Where(p =>
                                          p.Schoolclass.Id == schoolclassId &&
                                          p.Subject.Id == subjectId)
                                          .AsNoTracking()
                                          .ToListAsync();

            var schoolclass = new Schoolclass { Id = schoolclassId };
            var subject = new Subject { Id = subjectId };
            var schoolyear = new Schoolyear { Id = schoolyearId };

            // Make the navigation properties available during SaveChanges()
            context.Attach(schoolclass);
            context.Attach(subject);
            context.Attach(schoolyear);

            // DELETE
            var testTypesToRemove = testTypesFromDatabase.Except(testTypes, new TestTypeComparer()).ToList();
            context.TestTypes.RemoveRange(testTypesToRemove);

            // ADD
            var testTypesToAdd = testTypes.Where(t => t.Id == 0).ToList();  // 
            foreach (var testType in testTypesToAdd)
            {
                testType.Schoolclass = schoolclass;
                testType.Subject = subject;
                testType.Schoolyear = schoolyear;
            }
            context.TestTypes.AddRange(testTypesToAdd);

            // UPDATE
            var modifiedTestTypesToUpdate = testTypes.Except(testTypesToAdd.Concat(testTypesToRemove).ToList(), new TestTypeComparer()).ToList();
            foreach (var testType in modifiedTestTypesToUpdate)
            {
                testType.Schoolclass = schoolclass;
                testType.Subject = subject;
                testType.Schoolyear = schoolyear;
            }   
            context.UpdateRange(modifiedTestTypesToUpdate);

            await context.SaveChangesAsync();

            return await this.GetTestTypesConfigurationAsync(schoolclassId, subjectId);
        }

这篇关于无法跟踪实体类型“ TestType”的实例,因为已经跟踪了具有相同键的该类型的另一个实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆