【问题标题】:Asp.net core 2.0 The instance of entity type 'X' cannot be tracked because another instance with the key value 'Id:x' is already being trackedAsp.net core 2.0 无法跟踪实体类型“X”的实例,因为已在跟踪另一个具有键值“Id:x”的实例
【发布时间】:2017-09-01 07:08:51
【问题描述】:

我一直在做一个商店站点项目,使用最新的 VS2017 提供的 asp.net core spa 模板,并且遇到了一个我以前没有遇到过的问题,可能是因为到目前为止我的应用程序非常简单!

我知道问题出在哪里,但我无法解决。我有一个产品模型,它有一个“属性”集合和一个“变体”集合(不同的颜色大小等),这些变体也有属性,所以如果相同的属性出现在变体(VAttributes)中,就像已经在主要的“属性”中我收到错误

InvalidOperationException:实体类型的实例 无法跟踪“ProductAttribute”,因为另一个实例具有 键值“Id:2”已被跟踪。附加现有的 实体,确保只有一个具有给定键值的实体实例 已附上。

我找到的最佳答案在这里:https://stackoverflow.com/a/19695833/6749293

不幸的是,即使通过上述检查我得到了错误,我什至尝试制作一个附加属性列表,如果 vattribute 匹配列表中的一项,我没有附加它。事实上我发现即使我不附加 (_context.attach()) 任何 vAttributes,它仍然会抛出错误!。

这是有问题的代码:

    public async Task<Product> Create(Product product)
    {
        try
        {
            foreach (var variation in product.Variations)
            {

                foreach (var vAttr in variation.VAttributes)
                {

                    bool isDetached = _context.Entry(vAttr).State == EntityState.Detached;
                    if (isDetached)
                        _context.Attach(vAttr);

                }
            }
            foreach (var attribute in product.Attributes)
            {
                bool isDetached = _context.Entry(attribute).State == EntityState.Detached;
                if (isDetached)
                    _context.Attach(attribute);
            }
            foreach (var category in product.Categories)
            {
                _context.Attach(category);
                _context.Attach(category).Collection(x => x.Children);
            }

            _context.Products.Add(product);

            await Save();
            return product;
        }
        catch (Exception)
        {

            throw;
        }


    }

这3个对象的模型如下:

public class Product
{
    [Key, DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Description { get; set; }
    public string StockRef { get; set; }
    public DateTime? LastModified { get; set; }

    //image needed
    public ICollection<ProductCategory> Categories { get; set; }

    public ICollection<ProductAttribute> Attributes { get; set; }
    public ICollection<ProductVariation> Variations { get; set; }
    public Product()
    {
        Attributes = new List<ProductAttribute>();
        Variations = new List<ProductVariation>();
        Categories = new List<ProductCategory>();
    }
}

变化:

public class ProductVariation
{
    [Key, DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public DateTime? LastModified { get; set; }


    public virtual ICollection<ProductAttribute> VAttributes { get; set; }
    //needs images
    public decimal VPrice { get; set; }
    public string VStockRef { get; set; }
}

最后是属性:

public class ProductAttribute
{
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }

    [ForeignKey("AttributeCategory")]
    public int AttributeCategoryId { get; set; }
    public virtual AttributeCategory AttributeCategory { get; set; }


}

我在搜索时发现的大多数帮助更多地与将 repo 注入为单例或 HttpPut 方法有关,其中代码检查是否存在省略了 .AsNoTracking() 或者他们以某种方式拥有第二个实例是错误的,在我知道第二个实例的地方,我只是不知道如何防止它被跟踪!

编辑:我发现将 ProductVariation 模型上的外键添加到正在创建的产品失败,因为它只是一个临时键!?无论如何将其从变体模型中删除,因此更新了我的代码。还想我会添加一个我之前失败的尝试,这导致了所有的 foreach 循环。

            _context.AttachRange(product.Attributes);
            _context.AttachRange(product.Categories);
            _context.AttachRange(product.Variations);
            _context.Add(product);

【问题讨论】:

    标签: entity-framework asp.net-core asp.net-core-webapi asp.net-core-2.0


    【解决方案1】:

    我相信您可以让 EF 处理跟踪。

      public virtual bool Create(T item)
        {
            try
            {
                _context.Add(item);
                _context.SaveChanges();
                return true;
            }
            catch (Exception e)
            {
                return false;
            }
        }
    

    这允许您保存整个对象结构而无需担心附加项目。

    var newProduct = new Product();
    newProduct.Categories.Add(cat);
    newProduct.Attributes.Add(att);
    newProduct.Variations.Add(vari);
    Create(newProduct);
    

    【讨论】:

    • 很遗憾没有。我将现有实体的列表插入到新产品中,EF 尝试重新添加它们,但由于 id 已经存在而失败(我相信它默认将所有属性设置为 Add),这就是我一直使用附加的原因方法,如果所有 ProductVariations 都没有与 Product 相同的 ProductAttribute,则该方法有效,因此我需要做的是防止跟踪任何第二个实例。
    猜你喜欢
    • 2023-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 2020-01-31
    • 1970-01-01
    • 1970-01-01
    • 2019-12-29
    相关资源
    最近更新 更多