The instance of entity type 'Article' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked

c# entity-framework-core

Question

I am writing unit tests for my generic repository, but when I run my update method it fails.

My test method looks like this:

    private async Task TestUpdate()
    {
        var compare = testArticles[0];
        var article = await testInstance.SelectSingleAsync(new AdHocSpecification<Article>(x => x.Id == compare.Id), x => x.ArticleImages).ConfigureAwait(false);

        Compare(article, compare);

        article.Brand = "Air-Bam";
        article.DescriptionDutch = "Ter aldus dus juist wij zware. Hadden met karank afzien dat oog dus invoer oorlog. Oogenblik zoo volledige zin mag stoompomp schatkist. Per had met tot sinds batoe zelfs. Dit opgericht producten ontrukten schatkist het. Verkoopen ons die omgewoeld gebergten honderden dus het.";
        article.DescriptionFrench = "Comme verts mes comme ces nul fut. Et ah te avons rente rouge je. Il ainsi il cause oh croix utile or. Jeunesse poitrine en epanouir la reparler la. Jet noble force par arret ras voila votre peu. Les ete appareil supplice vit epandent. Collines dissiper cavalier octogone la magasins ca.";
        article.Discount = 80;
        article.IsDeleted = true;
        article.Price = 1000;
        article.Title = "Air Tone";

        await testInstance.UpdateAsync(article).ConfigureAwait(false);

        Assert.AreNotEqual(article.Brand, compare.Brand);
        Assert.IsNotNull(article.ArticleImages);
        Assert.IsFalse(article.ArticleImages.ToList().SequenceEqual(compare.ArticleImages.ToList()));
        Assert.AreNotEqual(article.DescriptionDutch, compare.DescriptionDutch);
        Assert.AreNotEqual(article.DescriptionFrench, compare.DescriptionFrench);
        Assert.AreNotEqual(article.Discount, compare.Discount);
        Assert.AreNotEqual(article.IsDeleted, compare.IsDeleted);
        Assert.AreNotEqual(article.Price, compare.Price);
        Assert.AreNotEqual(article.Title, compare.Title);
    }

The SelectSingleAsync and UpdateAsync methods look like the following:

    public virtual Task<TObj> SelectSingleAsync(Specification<TObj> spec, params Expression<Func<TObj, object>>[] includes)
    {
        return _context.Set<TObj>().Includes(includes).Where(spec.ToExpression()).AsNoTracking().FirstOrDefaultAsync();
    }

    public virtual async Task UpdateAsync(TObj obj)
    {
        _context.Set<TObj>().Update(obj);
        await _context.SaveChangesAsync().ConfigureAwait(false);
    }

When the Update method gets executed, an exception gets thrown:

System.InvalidOperationException: The instance of entity type 'Article' 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.

I do not understand why it is saying that it is already being tracked, as I am clearly using AsNoTracking() in my select method. What can I do to fix this?

Edit: The Article class looks like the following

public class Article:Entity<Guid>
{
    public string Title { get; set; }
    public string Brand { get; set; }
    public string DescriptionDutch { get; set; }
    public string DescriptionFrench { get; set; }
    public decimal Price { get; set; }
    public int Discount { get; set; }

    public ICollection<ArticleImage> ArticleImages { get; set; }

    public override bool Equals(object obj)
    {
        if (!(obj is Article article)) return false;
        return article.Title.Equals(Title)
            && article.Id.Equals(Id)
            && article.IsDeleted.Equals(IsDeleted)
            && article.Brand.Equals(Brand)
            && article.DescriptionDutch.Equals(DescriptionDutch)
            && article.DescriptionFrench.Equals(DescriptionFrench)
            && article.Price.Equals(Price)
            && article.Discount.Equals(Discount)
            && article.ArticleImages.SequenceEqual(ArticleImages);
    }
}

public abstract class Entity<TKey> where TKey : struct
{
    [Key] public TKey Id { get; set; }

    public bool IsDeleted { get; set; }
}

My context class looks like this:

public class ApplicationDbContext : IdentityDbContext<User>, IApplicationDbContext
{
    public ApplicationDbContext(DbContextOptions options)
        : base(options)
    {
    }

    public ApplicationDbContext()
    {
    }

    public DbSet<HomePageItem> HomePageItem { get; set; }
    public DbSet<Country> Country { get; set; }
    public DbSet<Address> Address { get; set; }
    public DbSet<Translation> Translation { get; set; }
    public DbSet<Article> Article { get; set; }
    public DbSet<ArticleImage> ArticleImage { get; set; }
}

Edit 2: Example of article that gets inserted:

        new Article
        {
            Brand = "Lorem",
            ArticleImages = new List<ArticleImage>{
                new ArticleImage
                {
                    Order = 0,
                    Url = "foo"
                },
                new ArticleImage
                {
                    Order = 1,
                    Url = "bar"
                }
            },
            DescriptionDutch = "Wier heft zien mont gaat zijn al en of. Wel brusch zin worden dienen bladen des vooral oosten. Nam behoeft noemden haalden elk. Stuit spijt enkel vogel oog een vindt geldt. Aangewend bezetting wijselijk arbeiders om is op antwerpen japansche af. Systemen planters vreemden kan hen passeert ons dichtbij dit. Met gevestigd wij financien als behoeften.",
            DescriptionFrench = "Air courtes reciter moi affreux croisee. La xv large en etais roidi ponts terre. Siens homme pic peu jeu glace beaux. Ca ma apres pitie sacre monde et voici. Battirent il echangent la croissent esplanade sortaient du ce. Fanatiques infanterie eux mon etonnement ecouterent imprudente assurances. Bambous fleurir ai arriere tu longues souffle etoffes un.",
            Discount = 10,
            IsDeleted = false,
            Price = 200,
            Title = "Tipfan"
        }

Code that does the insert:

    public virtual async Task InsertAsync(TObj obj)
    {
        _context.Set<TObj>().Add(obj);
        await _context.SaveChangesAsync().ConfigureAwait(false);
    }
1
1
6/7/2018 7:06:28 AM

Popular Answer

Try to repair your code like this:

     public class Article:Entity<Guid>
    {
        public string Title { get; set; }
        public string Brand { get; set; }
        public string DescriptionDutch { get; set; }
        public string DescriptionFrench { get; set; }
        public decimal Price { get; set; }
        public int Discount { get; set; }

        public ICollection<ArticleImage> ArticleImages { get; set; }

//add constructor, and initilize the id        
public Article(){
    this.Id = Guid.NewGuid();
    }

        public override bool Equals(object obj)
        {
            if (!(obj is Article article)) return false;
            return article.Title.Equals(Title)
                && article.Id.Equals(Id)
                && article.IsDeleted.Equals(IsDeleted)
                && article.Brand.Equals(Brand)
                && article.DescriptionDutch.Equals(DescriptionDutch)
                && article.DescriptionFrench.Equals(DescriptionFrench)
                && article.Price.Equals(Price)
                && article.Discount.Equals(Discount)
                && article.ArticleImages.SequenceEqual(ArticleImages);
        }
    }
0
10/10/2018 11:15:28 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow