Asp.net core 2.0实体类型的实例' X'无法跟踪,因为另一个具有键值的实例为“Id:x'已被跟踪

时间:2017-08-31 18:27:30

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

我一直在使用最新的VS2017提供的asp.net核心水疗模板开展一个商店网站项目,并且遇到了我以前没有的问题,可能是因为到目前为止我的应用程序相当简单!

我知道问题是什么,在哪里,我无法修复它。我有一个产品模型,其中包含"属性"以及" Variations" (不同的颜色大小等)和那些变体也有属性,所以如果相同的属性出现在变体(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);

1 个答案:

答案 0 :(得分:0)

我相信你可以让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);