当我尝试将SaveChanges()转换为上下文

时间:2018-05-26 00:04:42

标签: c# entity-framework

我创建了两个与我的两个类对应的列表:

//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",
            }
        };

当我尝试将这两个列表添加到我的上下文对象然后SaveChanges时,我收到了我提到的错误:

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

context.SaveChanges();

但是当我单独保存更改时,我没有得到例外。

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

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

这是为什么?我应该在每次修改数据库后保存更改吗?

1 个答案:

答案 0 :(得分:0)

要避免此类问题,请设置实体之间的关系并使用这些关系,而不是尝试手动设置FK ID。像EF这样的ORM旨在为您解决这个问题,因此可以利用这种能力。

如果照片有评论,评论中有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;}
}

请注意,我尚未添加PhotoID进行评论。如果您想搜索例如评论并导航回照片,那么您可以选择添加:

public virtual Photo Photo {get; set;}

但是,如果您不需要导航,那么我会避免添加它以保持简单。

要设置这些导航属性以便EF可以管理它们,我使用EntityTypeConfiguration映射。还有使用数据注释的方法,但我发现ETConfigs更可靠。

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.
   }
}

此示例适用于EF6,对于EFCore,您可以替换.Map()调用/ w

.HasForeignKey("PhotoID");

将使用shadow属性完成相同的操作。如果您确实希望在每个评论上引用照片,则可以在评论中添加虚拟属性,然后将.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); 
   }
}

现在,当您想要保存照片和评论时:

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

请注意,我们不会单独保存评论。 EF管理幕后的所有PK / FK。在SaveChanges之后,我们可以从实体属性中检索实体的PK。