简体   繁体   English

为什么实体框架只保存列表的最后一项?

[英]why does entity framework saves only the last item of a list?

I have 2 objects with one to many relation.我有 2 个具有一对多关系的对象。 I'm trying to add multiple ProductImages with the same ProductId to the data base, while using a generic repository.我正在尝试将具有相同 ProductId 的多个 ProductImage 添加到数据库中,同时使用通用存储库。

I have tried saving a list of ProductImage to a repository with dbSet.AddRange.我尝试使用 dbSet.AddRange 将 ProductImage 列表保存到存储库中。 after that i saved it with context.SaveChanges();之后我用 context.SaveChanges(); 保存它i have also tried looping trough the list of ProductImage and adding each item with dbSet.Add.and than context.SaveChanges().我还尝试通过 ProductImage 列表循环并使用 dbSet.Add.and 添加每个项目而不是 context.SaveChanges()。

repository methods:存储库方法:

    public virtual void Add(TEntity entity)
        {
            dbSet.Add(entity);
        }

        public virtual void AddRange(List<TEntity> entityList)
        {
            dbSet.AddRange(entityList);
        }
        public void Save()
        {
            context.SaveChanges();
    }

the result is the object saved to the data base is always the last one - but i want to save all of them.结果是保存到数据库的 object 始终是最后一个 - 但我想保存所有这些。

Edit the method for adding the Objects:编辑添加对象的方法:

        private  Task<int> InsertProductImagesToDB(List<ProductImageVM> productImages, int productId, List<IFormFile> imageFiles)
        {
            if (productImages?.Any()==true)
            {
                List<ProductImage> dbEntitys = new List<ProductImage>();
                for(int i=0; i< productImages.Count; i++)
                {
                    ProductImage p = productImages[i].ConvertToProductImageEntity(imageFiles[i], productId);
                    dbEntitys.Add(p);
                }
                ImagesRepository.AddRange(dbEntitys);
                ImagesRepository.Save();
                return Task.FromResult(dbEntitys.First().Id);//return first productImage as the main image
            }
            return Task.FromResult(-1);
        }

as some of you mentioned in the comments - the object constructor is not outside the loop.正如你们中的一些人在评论中提到的那样 - object 构造函数不在循环之外。 while debugging i can see the dbEntitys list contains 2 items with defferent values.在调试时,我可以看到 dbEntitys 列表包含 2 个具有不同值的项目。

image of the dbset after adding the objects before saving changes:在保存更改之前添加对象后的 dbset 图像: 在此处输入图像描述 db table after changes were saved:保存更改后的 db 表: 在此处输入图像描述

To expand on Steve's comment, the issue likely isn't with EF or adding the items to the DbSet, but rather with how you populate the entity list to save.为了扩展史蒂夫的评论,问题可能不在于 EF 或将项目添加到 DbSet,而在于您如何填充要保存的实体列表。

Take this for example:以此为例:

List<ProductImage> productImages = new List<ProductImage>();
Product product = context.Products.Single(x => x.ProductId == productId);
ProductImage productImage = new ProductImage();
for (int count = 1; count < 5; count++)
{
   productImage.ImageNumber = count;
   productImage.Product = product;
   productImages.Add(productImage);
}

// ...
context.ProductImages.AddRange(productImages);

The issue with the above code is that the loop is merely updating the same single reference of a ProductImage object.上述代码的问题在于,循环只是更新 ProductImage object 的同一个引用。 The list will contain 5 references to the same image and that image's Number will be "5".该列表将包含对同一图像的 5 个引用,并且该图像的编号将为“5”。

Instead:反而:

List<ProductImage> productImages = new List<ProductImage>();
Product product = context.Products.Single(x => x.ProductId == productId);
for (int count = 1; count < 5; count++)
{
   ProductImage productImage = new ProductImage();
   productImage.ImageNumber = count;
   productImage.Product = product;
   productImages.Add(productImage);
}

// ...
context.ProductImages.AddRange(productImages);

By moving the constructor for ProductImage into the loop, each image is a separate reference resulting in 5 unique items in the collection.通过将 ProductImage 的构造函数移动到循环中,每个图像都是一个单独的引用,从而在集合中产生 5 个唯一项。

The important detail is that if all of the images are for the same product, that you do use a single product reference for all images.重要的细节是,如果所有图像都用于同一产品,那么您确实对所有图像使用单一产品参考。 Whether that product is loaded from the database (above) or created as a new item.该产品是从数据库(上图)加载还是作为新项目创建的。 A common pitfall that developers new to EF make would be:新接触 EF 的开发人员会犯的一个常见陷阱是:

List<ProductImage> productImages = new List<ProductImage>();
for (int count = 1; count < 5; count++)
{
   Product product = new Product { ProductId = productId };
   ProductImage productImage = new ProductImage();
   productImage.ImageNumber = count;
   productImage.Product = product;
   productImages.Add(productImage);
}

// ...
context.ProductImages.AddRange(productImages);

Where they may have an existing Product ID that the user has selected, and don't want to hit the database to load it, so they just create a Product entity and set the ID thinking all will be good.他们可能有一个用户选择的现有产品 ID,并且不想访问数据库来加载它,所以他们只是创建一个产品实体并设置 ID,认为一切都会好起来的。 The issue here is that each Product instance will be a separate instance, and when you add the ProductImage to the DbSet, all untracked entities associated with that product image (Product in this case) will be treated as "Adds" as well.这里的问题是每个 Product 实例都是一个单独的实例,当您将 ProductImage 添加到 DbSet 时,与该产品图像(在本例中为 Product)关联的所有未跟踪实体也将被视为“添加”。 The result is that 5 new identical Products (with new IDs) would be added to the database provided the Product ID PK was configured as an Identity, or you'd get an error about inserting duplicate IDs.结果是,如果将产品 ID PK 配置为身份,则会将 5 个新的相同产品(具有新 ID)添加到数据库中,否则您会收到有关插入重复 ID 的错误。 With EF it is important to work with unique instances where you want unique records created, and work with a single instance (loaded from the DB, created new, or created as a stub and attached to the context) where you want to reference a single existing or new row.使用 EF 时,重要的是使用您希望创建唯一记录的唯一实例,以及使用您想要引用单个实例的单个实例(从数据库加载、创建新的或创建为存根并附加到上下文)现有的或新的行。

after banging my head against the wall for a few days - i finally got the solution.在把我的头撞在墙上几天之后 - 我终于找到了解决方案。

the problem was in my ProductImage Entity which looked like this:问题出在我的 ProductImage 实体中,如下所示:

   public class ProductImage : ImageProp, DBEntity
    {
        [Column("Name", TypeName = "nvarchar(200)"), Required, Display(Name = "שם"), MaxLength(200)]
        public string Name { get; set; }

        public Product Product { get; set; } 

        [Required]
        public int ProductId { get; set; }

    }

so the problem was this line:所以问题是这一行:

  public Product Product { get; set; } 

which apparently created a unique key for ProductId field in the data base table.这显然为数据库表中的 ProductId 字段创建了一个唯一键。 when i tried to add multiple ProductImages with the same ProductId, i got an sql exception that said i cannot insert duplicate value for ProductId.当我尝试添加具有相同 ProductId 的多个 ProductImage 时,我得到了一个 sql 异常,表示我无法为 ProductId 插入重复值。

removing this line solved the problem.删除这条线解决了这个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM