1

I know I can insert multiple entities using AddRange() and it will only make one trip to the database. In my case I'm inserting a single entity which has, for instance, 15 child entities. In this case Mini Profiler says I'm doing 15 duplicate queries, which afaik means that it takes 15 database trips no insert the child entities.

Question is - how can I bulk insert N child entities in one go? The amount of data in entities is incredibly small (few lines of text).

EDIT: For anyone having similar problem! Looks like there is no way to do so in EF. I ended up using SqlBulkCopy and except that you have to manually add related (child) entities it worked very well. Thanks guys!

//data u want to add to db
var data = someData.ToList();
System.Data.DataTable table = new System.Data.DataTable();
            table.Columns.Add("itemID", typeof(int));
            table.Columns.Add("Text", typeof(string)); 
            table.Columns.Add("Number", typeof(int)); 
            table.Columns.Add("ParentId", typeof(int));
            foreach (var entity in data)
            {
                DataRow row = table.NewRow();
                row["itemID"] = entity.SomeId;
                row["Text"] = entity.SomeText;
                row["Number"] = entity.SomeNumber;
                row["ParentId"] = entity.SomeParentId;
                table.Rows.Add(row);
            }
            using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["AppDbContext"].ConnectionString))
            {
                cn.Open();
                using (SqlBulkCopy bulkCopy = new SqlBulkCopy(cn))
                {
                    bulkCopy.DestinationTableName = "SomeInputFields";
                    bulkCopy.WriteToServer(table);
                }
                cn.Close();
            } 
Acuna Potata
  • 25
  • 1
  • 8
  • @MichalHainc not really. The one you posted is more about AddRange()/BulkInsert while my specifically points out that I'm having a problem with child entities. – Acuna Potata Apr 25 '15 at 19:55
  • Actually, it partially is a duplicate, but I wanted to figure out how do I bulk insert related data automatically, which wasn't covered in the question you provided. And as far as I understand now it simply isn't possible with EF at the moment. Or is it? -) – Acuna Potata Apr 26 '15 at 14:43

2 Answers2

0
  • Have you profiles your code?
  • How slow is it?
  • Is it definitely the SaveChanges()?

If it is slow, your best option will be:

  1. Insert the parent with no children and get ID.
  2. Update all child objects with parent ID
  3. BulkInsert ALL of the child entities using SqlBulkCopy

You need to decide whether you want to go down to optimizing this or not.

From my understanding EVERY insert is a separate query in EF. Even if you use AddRange.

Michal Ciechan
  • 13,492
  • 11
  • 76
  • 118
  • Yes I did profile the code with Miniprofiler.EF6. It really is slow bearing in my that the amount of data is extremely small. I.e., there can be 16 child entities (textboxes) with a single word in each one, which is a funny amount of data. And it will take up to 2 seconds to save them in DB. Imagine if I had a heavier data load.. Regarding "EVERY insert is a separate query in EF. Even if you use AddRange" - makes no sense to me - Miniprofiler sure proves this is a wrong statement. And yes, I know I can do bulk insert manually, but I wanted to see if there's a smarter way around this in EF – Acuna Potata Apr 26 '15 at 11:11
  • 2 seconds is definitely slow and unnacceptable. How far is the DB and Server away from each other? I am going to assume it is the latency that is causing it to be so slow. – Michal Ciechan Apr 26 '15 at 11:32
  • I apologize, looks like I was wrong - AddRange() does indeed makes a db trip for each item in list. And the other problem is that I cannot use BulkInsert due to the following error: "Already referencing a newer version of 'EntityFramework'." Seems like the package development been abandoned since April, 2014.. – Acuna Potata Apr 26 '15 at 11:35
  • ~2500 km... I'm usually getting ~200ms for most of my queries, except for the problem ones with many db trips. – Acuna Potata Apr 26 '15 at 11:38
  • The reason EF does single inserts is because it checks the rows affected on every statement, to make sure it got persisted correctly, and returns the primary key of the newly added entity. The SqlBulkCopy error is interesting. What version of EF are you using? And is it MS SQL server you are targeting? – Michal Ciechan Apr 26 '15 at 11:44
  • Oh my, I have confused you, sorry! I referred to the following package "EntityFramework.BulkInsert-ef6" when writing about the error -) And you are referring to SqlBulkCopy method, it all makes sense now. I didn't want to mess with store procs/sql queries, but it looks like the only option now. – Acuna Potata Apr 26 '15 at 11:49
0

Use a Table-Valued Parameter, and INSERT ... SELECT from that parameter.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • Mate, I didn't quite get how do I go about it in EF? – Acuna Potata Apr 26 '15 at 11:11
  • You would have to create a Stored Procedure in the Database that takes a Table-Valued Param, and then use that SProc in EF by creating a custom method that executes the given stored procedure with a `DataTable` as a parameter. – Michal Ciechan Apr 26 '15 at 11:36