简体   繁体   English

当我尝试将SaveChanges()转换为上下文时,EF中的“更新条目时发生错误”

[英]“An error occurred while updating the entries” in EF when I try to SaveChanges() to context

I've created two lists that corresponds to two of my classes: 我创建了两个与我的两个班级相对应的列表:

//Photo
        var photos = new List<Photo>{
            new Photo {
                Title = "Title1",
                Description = "Description1",
                CreatedDate = DateTime.Today
            }
        };

        //Comment
        var comments = new List<Comment>
        {
            new Comment{
                PhotoId = 1,
                UserName = "User1",
                Subject = "Comment1",
            }
        };

When I tried to add these two lists to my context object and then SaveChanges, I got the error I mentioned: 当我尝试将这两个列表添加到上下文对象然后添加SaveChanges时,出现了我提到的错误:

photos.ForEach(s => context.Photos.Add(s));
comments.ForEach(s => context.Comments.Add(s));

context.SaveChanges();

But when I saved the changes individually, I didn't get the exception. 但是,当我单独保存更改时,没有得到例外。

        photos.ForEach(s => context.Photos.Add(s));
        context.SaveChanges();

        comments.ForEach(s => context.Comments.Add(s));
        context.SaveChanges();

Why is this? 为什么是这样? Should I save changes after each modification of my DB? 每次修改数据库后是否应该保存更改?

To avoid issues like this, set up the relationships between your entities and use those relationships rather than trying to set FK IDs manually. 为避免此类问题,请在实体之间建立关系并使用这些关系,而不要尝试手动设置FK ID。 ORMs like EF are designed to work this detail out for you, so leverage that ability. 像EF这样的ORM旨在为您解决这些细节,因此请充分利用这一能力。

If a photo has comments, where a comment has a PhotoID column then set up the entities something like this: 如果照片中有评论,则评论中有一个PhotoID列,则可以这样设置实体:

public class Photo
{
   public int PhotoID {get; set;}
   public string Title {get; set;}
   public string Description {get; set;}

   private List<Comment> _comments = new List<Comment>();
   public virtual List<Comment> Comments 
   {
      get {return _comments;}
      set {_comments = value;}
   }
}

public class Comment
{
   public string UserName {get; set;}
   public string Subject {get; set;}
}

Note that I haven't added PhotoID to comment. 请注意,我尚未添加PhotoID进行评论。 If you want to search for comments for instance and navigate back to a Photo then you can optionally add: 例如,如果要搜索注释并导航回“照片”,则可以选择添加:

public virtual Photo Photo {get; set;}

However if you don't need that navigation, then I'd avoid adding it to keep things simple. 但是,如果您不需要该导航,那么我将避免添加它来使事情保持简单。

To set up these navigation properties so EF can manage them, I use EntityTypeConfiguration mappings. 为了设置这些导航属性,以便EF可以管理它们,我使用EntityTypeConfiguration映射。 There are also methods using data annotations, but I find ETConfigs more reliable. 也有使用数据注释的方法,但我发现ETConfig更可靠。

public class PhotoConfiguration : EntityTypeConfiguration<Photo>
{
   public PhotoConfiguration()
   {
      ToTable("Photos");
      HasKey(x => x.PhotoID)
         .Property(x => x.PhotoID)
         .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); // This informs EF that the database will be assigning the PK.

      HasMany(x => x.Comments)
         .WithRequired()
         .Map(x => x.MapKey("PhotoID")); // This tells EF to join comments to a Photo /w the PhotoID on the Comment table. HasMany says a Photo has many comments, and WithRequired() points to a non-nullable FK on Comment, but no navigation property coming back to Photo.
   }
}

This example is for EF6, for EFCore you can replace the .Map() call /w 此示例适用于EF6,对于EFCore,您可以替换.Map()调用/ w

.HasForeignKey("PhotoID");

which will accomplish the same thing with a shadow property. 使用shadow属性可以完成相同的操作。 If you do want a reference to Photo on each Comment, then you can add the virtual property in Comment, then replace the .WithRequired() with .WithRequired(x => x.Photo) and this will set up the relationship. 如果确实要在每个Comment上引用Photo,则可以在Comment中添加虚拟属性,然后将.WithRequired()替换为.WithRequired(x => x.Photo) ,这将建立关系。

public class CommentConfiguration : EntityTypeConfiguration<Comment>
{
   public CommentConfiguration()
   {
      ToTable("Comments");
      HasKey(x => x.CommentID)
         .Property(x => x.CommentD)
         .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 
   }
}

Now when you want to save a photo and a comment: 现在,当您要保存照片和评论时:

   var photo = new Photo 
   {
      Title = "Title1",
      Description = "Description1",
      CreatedDate = DateTime.Today,
      Comments = new[] 
      {
         New Comment { UserName = "User1", Subject = "Comment1" }
      }.ToList()
   };
   context.Photos.Add(photo);
   context.SaveChanges();

Note that we don't save Comments separately. 请注意,我们不会单独保存评论。 EF manages all of the PK/FK behind the scenes. EF在后台管理所有PK / FK。 After the SaveChanges we can retrieve the PKs of our entities from the entity properties. 保存更改后,我们可以从实体属性中检索实体的PK。

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

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