locked
EF Core and exception in AddRange RRS feed

  • Question

  • User1993186009 posted

    My app has the following code:


    [Table("prom_term", Schema = "demo")]
        public class PromTerm
        {
            [Key]
            [Column("promotion_terminal_id")]
            [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
            public int Id { get; set; }
            [Column("promotion_id")]
            public int Promotionld { get; set; }
            [ForeignKey("Promotionld")]
            public DbPromotion Promotion { get; set; }
            [Column("pos_terminal_id")]
            public string POSTerminalld { get; set; }
            [Column("retailer_name")]
            public string RetailerName { get; set; }
            [Column("promotion_report_period_id")]
            public int ReportPeriodld { get; set; }
            [ForeignKey("ReportPeriodId")]
            public PromReportPeriod RepoortPeriod { get; set; }
        }
    
        public class FamilyTeamSvcDbContext : DbContext
        {
    
            ...
            public DbSet<PromTerm> PromotionTerminals { get; set; }
        }
    
                using var ctx = new FamilyTeamSvcDbContext(options);
                var promoTerminals = new List<PromTerm>{
                        new PromTerm
                        {
                            POSTerminalId="777777", 
                            RetailerName="8888"
                        },
                        new PromTerm
                        {
                            POSTerminalId="333",
                            RetailerName="AAA"
                          },
                          new PromTerm
                        {
                            POSTerminalId="qqq",
                            RetailerName="AAA"
                        },
                        new PromTerm
                        {
                            POSTerminalId="qqq",
                            RetailerName="BBB"
                        }
                    }
                    ;
                promoTerminals.ForEach(x => {
                    x.Promotionld = 1;
                    x.ReportPeriodld = 2;
                    //ctx.PromotionTerminals.Append(x);
                    }
                );
    
                ctx.PromotionTerminals.AddRange(promoTerminals);

    Right at the last line it throws this exception:

    System.InvalidOperationException : The instance of entity type 'PromTerm' cannot be tracked because another instance with the same key value for {'PromotionId', > 'POSTerminalId'} 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.
    Stack Trace:
    IdentityMap`1.ThrowIdentityConflict(InternalEntityEntry entry)
    IdentityMap`1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)
    IdentityMap`1.Add(TKey key, InternalEntityEntry entry)
    NullableKeyIdentityMap`1.Add(InternalEntityEntry entry)
    StateManager.StartTracking(InternalEntityEntry entry)
    InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)
    InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges, Boolean modifyProperties, Nullable`1 forceStateWhenUnknownKey)
    EntityGraphAttacher.PaintAction(EntityEntryGraphNode`1 node)
    EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode`1 node, Func`2 handleNode)
    EntityGraphAttacher.AttachGraph(InternalEntityEntry rootEntry, EntityState targetState, EntityState storeGeneratedWithKeySetTargetState, Boolean  forceStateWhenUnknownKey)
    InternalDbSet`1.SetEntityState(InternalEntityEntry entry, EntityState entityState)

    InternalDbSet`1.SetEntityStates(IEnumerable`1 entities, EntityState entityState)

    InternalDbSet`1.AddRange(IEnumerable`1 entities)

    Why does it treat 'PromotionId' +'POSTerminalId' as a key still a bit beyond me. My schema does not have these fields as a multi-column key. But there's one more weird behavior — if I uncomment Append() and comment AddRange(), then adding starts working. What am I doing wrong?

    Friday, March 12, 2021 8:32 PM

All replies

  • User475983607 posted

    The error means you created two different DbContexts.  You should use constructor injection  rather than instantiating a new DbContext the PromotionTerminals method.  

     using var ctx = new FamilyTeamSvcDbContext(options);

    See the official DI reference documentation.

    https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0

    Friday, March 12, 2021 8:47 PM
  • User1993186009 posted

    Nope, the code has the same behavior even w/o DI, and I am deadly sure that there's only one context.

    Friday, March 12, 2021 8:50 PM
  • User1686398519 posted

    Hi Gatwick,  

    1. public string POSTerminalld { get; set; }
      POSTerminalId="777777",
      1. The property name in your Model seem to be incorrect.
        1. You can check the part I marked with color.
        2. I suggest you to check the code in your project.
    2. The instance of entity type 'PromTerm' cannot be tracked because another instance with the same key value for {'PromotionId', > 'POSTerminalId'} is already being tracked
      if I uncomment Append() and comment AddRange(), then adding starts working.
      1. Very strange, I used the code you provided and added the missing code, and did not reproduce your problem.
      2. This problem usually occurs because your context has been shared by multiple requests, which means that the entity you are editing has been tracked.
      3. You can use AsNotracking.

    Best Regards,

    YihuiSun

    Monday, March 15, 2021 6:36 AM