2017-04-13 73 views
0

我嘗試爲Asp.net核心DBContext實施XUnit測試,但是出現了以下錯誤。EF核心更新無法跟蹤實體類型「Ads」的實例

消息:System.InvalidOperationException:實體類型「Ads」的實例無法跟蹤,因爲具有相同鍵的此類型的另一個實例已被跟蹤。添加新實體時,對於大多數鍵類型,如果未設置鍵(即,如果鍵屬性被指定爲其類型的默認值),則將創建唯一的臨時鍵值。如果您明確地爲新實體設置關鍵值,請確保它們不與現有實體衝突或爲其他新實體生成的臨時值衝突。在附加現有實體時,確保只有具有給定鍵值的一個實體實例附加到上下文。

這裏是我當前的代碼:

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

任何幫助,將不勝感激。

回答

2

您是new「荷蘭國際集團建立自己的實體的時候,你應該得到你已經從上下文補充說,實體:

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

有了這個代碼,實體框架是在說,「嘿,我已經有了一個具有該鍵的實體(檢查你的構造函數,你將一個實體放在同一個Id中),但是這個對象;我不知道該怎麼做(因爲它來自外部,已經存在)」。

你可以把它改成正是你在前面的測試中做什麼:

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

你的意思是我不能用'_dbSet.Update(實體);'?在我的選擇中,當我使用'entity.ObjectState = ObjectState.Modified'時,它可以接受一個新的對象。否則,我需要逐一設置。 –

+0

這個問題不在'_dbSet.Update(entity)'調用中,它存在於上下文中使用的對象中。您可以更改您在更新測試中使用的'New Ads()'以從上下文中檢索它,或者,您可以執行您正在做的事情,並首先調用'Context.Attach(entity)',這樣EF可以調和你從外面傳入的東西。 – steamrolla

相關問題