locked
Save multiple parent child record in foreach loop (Multiple added entities may have the same primary key.) RRS feed

  • Question

  • User1624600859 posted

    Hi,

    I have the following code

    <div>

    public void InsertAttachments(List<string> attachmentPaths, string myData)
            {
                var context = dbProvider.GetContext();
                foreach (var fromFile in attachmentPaths)
                {
                    string folderName = CopyFile(fromFile);
                    var att = new Attachment()
                    {
                        File_Path = folderName,
                        FileName = Path.GetFileName(fromFile),
                        DateInserted = DateTime.UtcNow
                    };
    
                    context.AttachmentsMyData.Add(new AttachmentMyData()
                    {
                        Attachment = att,
                        MyData = myData
                    });
                     context.SaveChanges();// Bad to do it here
                }
                 context.SaveChanges();// Here gives error 
            }                

    Now concern here is that savechanges is called within foreach loop, which to me seems to be bad, as we are communicating with db again and again. But if I place the savechanges out of foreach loop, I get Multiple added entities may have the same primary key. My EF version is 4.2 so no addrange option as we have in EF 6.0.   So how to avoid db.savechanges within foreach loop. </div>

    Monday, March 16, 2020 6:29 AM

All replies

  • User303363814 posted

    What is the primary key on AttachmentsMyData?

    If you use an autogenerated identity you won't have a problem.

    Monday, March 16, 2020 11:42 PM
  • User-719153870 posted

    Hi ronnyrunatserver,

    But if I place the savechanges out of foreach loop, I get Multiple added entities may have the same primary key.

    Please provide more information including the definition code of your classes ,sample data and anything else necessary so that we can provide a precise solution.

    According to this doc, we can put the savechanges() method out of the foreach without any error, so we need more information to reproduce the issue.

    var students = new List<Student>
                {
                new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
                new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
                new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
                new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
                new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
                new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
                new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
                new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
                };
    
                students.ForEach(s => context.Students.Add(s));
                context.SaveChanges();

    Best Regard,

    Yang Shen

    Tuesday, March 17, 2020 2:42 AM
  • User-17257777 posted

    Hi ronnyrunatserver,

    I get Multiple added entities may have the same primary key.

    For this issue, maybe you can provide us more details including the classes related and your dbcontext, then we can reproduce your problem and find a solution.

    Besides, If you cannot use AddRange, set Entity Framework AutoDetectChanges to false. The Add method DetectChanges after every records added. By disabling AutoDetectChanges, the DetectChanges method will only be invoked when you do it. Steps are as follow

    1. SET AutoDetectChangesEnabled = false
    2. CALL DetectChanges before SaveChanges
    3. SaveChanges

    Best Regards,

    Jiadong Meng

    Tuesday, March 17, 2020 6:38 AM
  • User1624600859 posted

    @PaulTheSmith I am using Autogenerated identity option in table.. Further, as can be seen in shared code above, attachments are multiple.

    Parent table is Attachments whose reference is in attachmentsMyData..

    Also, if you have to do this i.e. saving multiple parent-child records without using savechanges() within foreach loop. Then what would be your approach. As calling db.savechanges() within foreach is not a good practice as in this case we are communicating with DB for every parent-child pair.

    Tuesday, March 17, 2020 7:21 AM
  • User1624600859 posted

    Hi ronnyrunatserver,

    ronnyrunatserver

    I get Multiple added entities may have the same primary key.

    For this issue, maybe you can provide us more details including the classes related and your dbcontext, then we can reproduce your problem and find a solution.

    Besides, If you cannot use AddRange, set Entity Framework AutoDetectChanges to false. The Add method DetectChanges after every records added. By disabling AutoDetectChanges, the DetectChanges method will only be invoked when you do it. Steps are as follow

    1. SET AutoDetectChangesEnabled = false
    2. CALL DetectChanges before SaveChanges
    3. SaveChanges

    Best Regards,

    Jiadong Meng

    Still getting same error

    Point here is, how we can save mutiple parent child records without using savechanges within foreach loop?

    Tuesday, March 17, 2020 7:35 AM
  • User-17257777 posted

    Hi ronnyrunatserver,

    SaveChanges() inside or outside the foreach loop are both OK, the difference between them is the performance.

    https://stackoverflow.com/a/11134297/11965297

    I get Multiple added entities may have the same primary key.

    The error is related to your classes, please show us them.

    Best Regards,

    Jiadong Meng

    Tuesday, March 17, 2020 8:38 AM
  • User-719153870 posted

    Hi ronnyrunatserver,

    I tried to reproduce the issue with EF4.2 as you said, but the demo can not be build successfully with various of problems caused by the old version of EF.

    So i updated it to EF6.4 which seems to be the latest version and the demo works perfectly, even if i put the the context.SaveChanges(); out of the foreach loop, the demo can work as expected.

    Below is the demo i tested:

        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    List<string> list = new List<string> { "name1", "name2", "name3" };
                    InsertAttachments(list, "Titlettt");
                    Console.WriteLine("Success!");
                }
                catch (Exception ex)
                {
                    throw (ex);
                }
            }
    
            public static void InsertAttachments(List<string> attachmentPaths, string myData)
            {
                var context = new BloggingContext();
                foreach (var item in attachmentPaths)
                {
                    string Name = item;
                    var att = new Blog()
                    {
                        Name = Name
                    };
                    context.Posts.Add(
                        new Post()
                        {
                            Blog = att,
                            Title = myData
                        }
                        );
                    //context.SaveChanges();
                }
                context.SaveChanges();
            }
        }
    
        public class Blog
        {
            [Key]
            public int BlogId { get; set; }
            public string Name { get; set; }
        }
    
        public class Post
        {
            [Key]
            public int PostId { get; set; }
            public string Title { get; set; }
    
            public int BlogId { get; set; }
            public Blog Blog { get; set; }
        }
    
        public class BloggingContext : DbContext
        {
            public BloggingContext() : base("DConString")
            { }
            public DbSet<Blog> Blogs { get; set; }
            public DbSet<Post> Posts { get; set; }
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
            }
        }

    Here's the result of this demo:

    And the tables created with data:

    In conclusion, i would suggest you to update your EF to the latest. Or, you could provide more information including the table structures, error information and anything else you think it's necessary for the community to reproduce the issue. Thanks!

    Best Regard,

    Yang Shen

    Wednesday, March 18, 2020 3:02 AM
  • User1624600859 posted

    jiadongm

    Hi ronnyrunatserver,

    SaveChanges() inside or outside the foreach loop are both OK, the difference between them is the performance.

    https://stackoverflow.com/a/11134297/11965297

    ronnyrunatserver

    I get Multiple added entities may have the same primary key.

    The error is related to your classes, please show us them.

    Best Regards,

    Jiadong Meng

    Apologize as I haven't metioned the EF version which is 4.2 not 6 onwards. I working on EF 4.2.. And agree to your performance point, that I am already aware of..But can't implement outside foreach loop due to the multiple added entities may have the same primary key error. Seems its not possible in #F 4.2, due to which am getting this error. So was looking for an alternate option or any settings that can perform this successfully in EF 4.2.

    Wednesday, March 18, 2020 6:17 AM
  • User1624600859 posted

    This is what I feel, that its a version issue, this works fine in ef 6 as you have mentioned, but not in EF 4.2, due to which I am facing the issue of Multiple primary key. And I can't upgrade it due to the application being in maintenance mode.

    Wednesday, March 18, 2020 6:24 AM