question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

SaveChanges takes a lot of time due to expensive looping in method MetadataHelper.GetAssociationsForEntitySet(EntitySetBase entitySetKey)

See original GitHub issue

This issue was discussed earlier in 2012 on MSDN forums but it didn’t go anywhere. We now have a genuine need to fix this problem as described here:

Entity Model:

Order - root entity OrderItem - 1-M child of Order

Order and OrderItem have a few FK associations with other master entities such as Customer and Product.

Scenario:

We are creating a new Order and many OrderItems (~600,000) within a single instance of DbContext and calling SaveChanges in the end.

We found that DbContext.SaveChanges was taking a lot of time, so we decided to run our application with dotTrace Profiler, which reported following method as a hot-spot taking almost 70% time:

System.Data.Common.Utils.MetadataHelper.GetAssociationsForEntitySet(EntitySetBase)

DBContext Settings:

  1. Configuration.AutoDetectChangesEnabled = false;
  2. Configuration.ValidateOnSaveEnabled = false;

Potential Solution: We made a small change to this method to avoid looping and use a dictionary instead to lookup for associations.

private static readonly ConcurrentDictionary<EntitySetBase, List<AssociationSet>> _associationSetsForEntitySet = new ConcurrentDictionary<EntitySetBase, List<AssociationSet>>();

Then fixed the method to use the dictionary as follows:

    // requires: entitySet
    // effects: Returns the associations that occur between entitySet
    // and other entitySets. If none is found, returns an empty set
    internal static List<AssociationSet> GetAssociationsForEntitySet(EntitySetBase entitySetKey)
    {
        DebugCheck.NotNull(entitySetKey);

        return _associationSetsForEntitySet.GetOrAdd(
            entitySetKey, entitySet =>
            {
                var result = new List<AssociationSet>();

                foreach (var extent in entitySet.EntityContainer.BaseEntitySets)
                {
                    if (Helper.IsRelationshipSet(extent))
                    {
                        var assocSet = (AssociationSet)extent;
                        if (IsExtentAtSomeRelationshipEnd(assocSet, entitySet))
                        {
                            result.Add(assocSet);
                        }
                    }
                }
                return result;
            });
    }

The performance indeed improved significantly as seen in the attached profiler snapshots: snapshots of getassociationsforentityset before and after optimization

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:1
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
ravi-pathakcommented, Oct 16, 2017

@ajcvickers I will submit a pull request soon. Thanks for your comment.

0reactions
ajcvickerscommented, Oct 23, 2017

@ravi-pathak Thanks for finding that. We plan to release EF6.2 soon–we have been having some infrastructure issues that has delayed a number of things, but as of the end of last week we seem to be past them, so we’re going to try to get this out soon now.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Entity framework performance issue, saveChanges is very ...
The reason I put savechanges in the foreach is because the records are relative big and the run time is costly (usually takes...
Read more >
Keeping a DbContext open overtime eventually slows ...
Every time after we successfully save changes we will set the state of all entries to Unchanged, but the next time you call...
Read more >
c# Performance Issue while saving to DB - Microsoft Q&A
Just looking at the code, move the SaveChanges call outside the foreach loop. Then it does all the work and then saves once....
Read more >
Entity Framework doesn't like SaveChanges in a for loop.. ...
So I'm working on a program which is a service that loops through records and calculates averages and then saves the changes to...
Read more >
EF Core Bulk SaveChanges | Optimize Data Saving ...
The SaveChanges method makes it quite slow/impossible to handle a scenario that requires to save a lot of entities due to the number...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found