title: Need to speed up writing large object graph to database with Entity Framework
body: <p>I'm using EntityFramework Core on my current project.  In this project, I have an API endpoint that accepts a large (4,000K) text file.  The endpoint reads and parses the file and converting the data into an object graph.</p>
  
  <p>I then need to write the entire graph to a SQL database.  After parsing the text file, I wind up with about 20,000 objects in this object graph.  </p>
  
  <p>The graph typically has one Transaction.  The Transaction has about 5000 Subscribers and each Subscriber has an average of 4 Benefits.  Each Dates collection will have 1 or 2 DateRanges.  Rejections are usually empty.</p>
  
  <p>My object graph looks basically like this:</p>
  
  <pre><code>public class Transaction {
     public int Id {get; set;}
     ...  // Other properties
     public ICollection&lt;Subscriber&gt; Subscribers {get; private set;}
     public ICollection&lt;TranRejection&gt; Rejections {get; private set;}
  }
  
  public class Subscriber {
     public int Id {get; set;}
     public int TransactionId {get; set;}  //Foreign Key
     ... // Other properties
     public ICollection&lt;Benefit&gt; Benefits {get; private set;}
     public ICollection&lt;SubscriberRejection&gt; Rejections {get; private set;}
     public ICollection&lt;SubscriberDateRange&gt; Dates {get; private set;}
  }
  
  public class Benefit {
     public int Id {get; set;}
     public int SubscriberId {get; set;}  //Foreign Key
     ... // Other properties
     public ICollection&lt;BenefitRejection&gt; Rejections {get; private set;}
     public ICollection&lt;BenefitDateRange&gt; Dates {get; private set;}
  }
  
  //This abstract class w/ empty subclasses is done to take advantage of TPH
  //so that all dates get stored in a single table
  public abstract class DateRange {
     public int Id {get; set;}
     public int ParentId {get; set;}
     public string DateCode {get; set;}
     public DateTime BeginRange {get; set;}
     public DateTime? EndRange {get; set;}
  }
  
  public class BenefitDateRange : DateRange {}
  public class SubscriberDateRange : DateRange {}
  
  //Rejection class is handled very similar to DateRange
  </code></pre>
  
  <p>My EF Mappings look something like this.  (Only including important bits to help see relationships).</p>
  
  <pre><code>builder.Entity&lt;DateRange&gt;().ToTable("dateranges")
    .HasDiscriminator&lt;string&gt;("rangetype")
    .HasValue&lt;BenefitDateRange&gt;("benefit")
    .HasValue&lt;SubscriberDateRange&gt;("subscriber");
  builder.Entity&lt;DateRange&gt;().HasKey(r =&gt; r.Id);
  
  builder.Entity&lt;Transaction&gt;().HasMany(t =&gt; t.Subscribers).WithOne()
     .HasForeignKey(s =&gt; s.TransactionId);
  
  builder.Entity&lt;Subscriber&gt;().HasMany(s =&gt; s.Benefits).WithOne()
     .HasForeignKey(b =&gt; b.SubscriberId);
  
  builder.Entity&lt;Subscriber&gt;().HasMany(s =&gt; s.Dates).WithOne()
     .HasForeignKey(d =&gt; d.ParentId);
  
  //Similar mappings for Benefit.Dates
  //Rejections are using TPH just like DateRanges
  </code></pre>
  
  <p>I tried saving to the database by saving pieces individually -- i.e saving transaction with no subscribers and then saving each subscriber, etc.  That takes at least 30 minutes.</p>
  
  <p>I then switched to saving the entire graph at once like this:</p>
  
  <pre><code>_dbContext.AddRange(transactions);
  _dbContext.SaveChanges();
  </code></pre>
  
  <p>That takes about 5 minutes.  However, this is part of an API call and I'd like to speed this up.  Is there a faster way to save this whole graph to the database?  Should I not be using EF for this?</p>