EF Core 更新无法跟踪实体类型 'Ads' 的实例

EF Core Update The instance of entity type 'Ads' cannot be tracked

我尝试为 Asp.net Core DBContext 实施 XUnit 测试,但出现以下错误。

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

这是我当前的代码:

    public class AdsServiceTest
{
    private readonly DbContextOptions<SensingSiteDbContext> _options;
    private readonly SensingSiteDbContext _context;
    private readonly AdsService _AdsService;
    public AdsServiceTest()
    {
        //initialize db options
        _options = new DbContextOptionsBuilder<SensingSiteDbContext>()
            .UseInMemoryDatabase()
            .Options;
        //get service
        _context = new SensingSiteDbContext(_options);
            //initialize dbcontext
            List<Ads> listAds = new List<Ads>() {
                new Ads(){  Id=1,AdsName="Ads1", Deleted=false},
                new Ads(){  Id=2,AdsName="Ads1", Deleted=false},
                new Ads(){  Id=3,AdsName="Ads1", Deleted=false}
            };
         _context.Advertisements.AddRange(listAds);
            //context.Advertisements
            BaseLib.SSDbContext<Ads, AdsService> ssDbContent = new BaseLib.SSDbContext<Ads, AdsService>(_context);
            _AdsService = ssDbContent.GetService((x, y) => new AdsService(x, y));

    }
    [Theory]
    [InlineData(1)]
    public void FindById(int id)
    {
        Ads adsResult = _AdsService.FindById(id);
        Ads adsTarget = _context.Advertisements.Find(adsResult.Id);
        Assert.True(adsTarget.Equals(adsResult));
    }
    //Failed by error System.InvalidOperationException : The instance of entity type 'Ads' cannot be tracked because another instance of this type with the same key is already being tracked
    [Fact]
    public void Update()
    {
        Ads adsResult = new Ads() { Id = 1, AdsName = "UpdateAds1" };
        _AdsService.UpdateAds(adsResult);
        Ads adsTarget = _context.Advertisements.Find(adsResult.Id);
        Assert.True(adsTarget.Equals(adsResult));
    }
}

查找没有问题,更新失败。 AdsService 实现调用 SensingSiteDbContext。看来我需要为 SensingSiteDbContext 使用作用域生命周期。但是,我不知道如何实现它。
我已更改 ObjectState 以进行更新。

        public virtual void Update(TEntity entity)
    {
        entity.ObjectState = ObjectState.Modified;
        _dbSet.Update(entity);            
        _context.SyncObjectState(entity);
    }

如有任何帮助,我们将不胜感激。

您正在 new 创建您自己的实体,此时,您应该只获取您已经从上下文中添加的实体:

Ads adsResult = new Ads() { Id = 1, AdsName = "UpdateAds1" };
_AdsService.UpdateAds(adsResult);

使用此代码,Entity Framework 表示 "Hey, I already have an entity with that key (check your constructor, you're putting an entity in with that same Id), but this object; I don't know what to do with it (because it came from outside with a key that already exists)"。

您可以将其更改为您在之前的测试中所做的:

Ads adsResult = _AdsService.FindById(id);
//do your changing here
_AdsService.UpdateAds(adsResult);