2017-04-13 5 views
0

Asp.net Core DBContextのXUnitテストを実装しようとしましたが、エラーが発生しました。EFコアアップデートエンティティタイプ 'Ads'のインスタンスはトラッキングできません

メッセージ:System.InvalidOperationException:エンティティタイプ 'Ads'のインスタンスは、同じキーを持つこのタイプの別のインスタンスが既にトラッキングされているため、トラッキングできません。新しいエンティティを追加する場合、ほとんどのキータイプでは、キーが設定されていない場合(キープロパティにそのタイプのデフォルト値が割り当てられている場合)、一意の一時キー値が作成されます。新しいエンティティのキ​​ー値を明示的に設定する場合は、既存のエンティティや他の新しいエンティティ用に生成された一時的な値と衝突しないようにしてください。既存のエンティティをアタッチする場合は、指定されたキー値を持つエンティティインスタンスが1つだけコンテキストにアタッチされていることを確認します。

は、ここに私の現在のコードです:

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 for Updateを変更しました。

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

助けてください。

答えて

2

独自のエンティティをnew「アップINGのしている、あなたはちょうどあなたがすでにコンテキストから追加したそのエンティティを取得する必要時に、このコードで

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

を、Entity Frameworkのは、ちょっと」と言っています私はすでにそのキーを持つエンティティを持っています(あなたのコンストラクタをチェックして、同じIDでエンティティを入れています)が、このオブジェクトは、私はそれをどうしたらいいのかわかりません。もう存在している)"。

あなたは、前のテストでやっている正確に何にそれを変更することができます:あなたは私が `_dbSet.Update(エンティティ)を使用することはできません

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

意味しますか;'?私の選択では、 'entity.ObjectState = ObjectState.Modified'を使うと、新しいオブジェクトを受け入れることができます。そうでなければ、私は提出書類を一つずつセットする必要があります。 –

+0

問題は '_dbSet.Update(エンティティ)'呼び出しにはなく、コンテキストでどのオブジェクトを使用しているかにあります。更新テストで使用している 'new Ads()'をコンテキストから取得するか、あなたがやっていることを実行して、 'Context.Attach(entity)'を最初に呼び出すことができます。外部から渡すオブジェクトを調整します。 – steamrolla

関連する問題