首页 文章

无法跟踪实体类型'Article'的实例,因为已跟踪具有{'Id'}相同键值的另一个实例

提问于
浏览
1

我正在为我的通用存储库编写单元测试,但是当我运行我的更新方法时它失败了 .

我的测试方法如下所示:

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);
    }

SelectSingleAsync和UpdateAsync方法如下所示:

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);
    }

执行Update方法时,会抛出异常:

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

我不明白为什么它说它已被跟踪,因为我在我的select方法中明显使用 AsNoTracking() . 我该怎么做才能解决这个问题?

编辑:Article类如下所示

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; }
}

我的上下文类看起来像这样:

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; }
}

编辑2:插入的文章示例:

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"
        }

执行插入的代码:

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

2 回答

  • 0

    尝试像这样修复你的代码:

    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

    从数据库中获取数据并迭代它时,如:

    var dataObject = await dbContext.Table.where(x=>x.UserId == model.UserId).TolistAsync();
    foreach(var item in dataObject)
    { 
    
    }
    

    不要创建另一个对象,将获取的对象直接传递给Delete或使用它来更新,因为DbContext正在跟踪它所获取的对象,而不是您创建的对象 . 例如:

    //错误的代码

    var dataObject = await dbContext.Table.where(x=>x.UserId == model.UserId).TolistAsync();
    foreach(var item in dataObject)
    { 
       var x=new DataObject()
       {
          x=item.Id
       };
       dbContext.Table.Remove(x);
    }
    

    您必须将最初提取的实例传递给Remove()方法,请参阅:

    var dataObject = await dbContext.Table.where(x=>x.UserId == model.UserId).TolistAsync();
    foreach(var item in dataObject)
    { 
        dbContext.Table.Remove(item);
    }
    

相关问题