【问题标题】:EF Core Update The instance of entity type 'Ads' cannot be trackedEF Core 更新无法跟踪实体类型“广告”的实例
【发布时间】:2017-09-09 12:36:54
【问题描述】:

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

消息:System.InvalidOperationException:无法跟踪实体类型“广告”的实例,因为已在跟踪具有相同键的该类型的另一个实例。添加新实体时,对于大多数键类型,如果没有设置键(即,如果键属性为其类型分配了默认值),则会创建一个唯一的临时键值。如果您为新实体显式设置键值,请确保它们不会与现有实体或为其他新实体生成的临时值发生冲突。附加现有实体时,请确保只有一个具有给定键值的实体实例附加到上下文。

这是我当前的代码:

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

任何帮助将不胜感激。

【问题讨论】:

    标签: entity-framework-core xunit


    【解决方案1】:

    你正在new'ing 自己的实体,什么时候,你应该从上下文中获取你已经添加的实体:

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

    使用这段代码,实体框架说,“嘿,我已经有一个带有该键的实体(检查你的构造函数,你正在使用相同的 Id 放入一个实体),但是这个对象;我不知道如何处理它(因为它来自外部,带有一个已经存在的密钥)”。

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

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

    【讨论】:

    • 你的意思是我不能使用_dbSet.Update(entity);?在我的选择中,当我使用entity.ObjectState = ObjectState.Modified 时,它可以接受一个新对象。否则,我需要一一设置。
    • 问题不在于_dbSet.Update(entity) 调用,而在于您在上下文中使用的对象。您可以更改您在更新测试中使用的 new Ads() 以从上下文中检索它,或者,您可以执行您正在执行的操作,然后首先调用 Context.Attach(entity),以便 EF 可以协调您从中传递的对象外面。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-29
    • 2021-04-23
    • 2021-05-04
    • 2019-10-28
    • 1970-01-01
    • 2019-01-10
    • 1970-01-01
    相关资源
    最近更新 更多