-1

I around have 400,000 records which is coming from file. But after inserting 30000 to 33000 of records it is throwing error 'System.OutOfMemoryException'

In my system i have 8gb of ram i think it is enough for this. And i inserting bunch of records like 500 records at a time using this code.

this._context.AutoDetectChangesEnabled = false;

if(Counter % 500 == 0)
    _context.SaveChanges();

i tried all possible changes and do lots of r & d and also find all possible solution on this stack overflow site but it can't help.

I am using nopcommerce basically for this context using

private readonly IDbContext context;

And also let me know if any confusion!

public partial class EfRepository<T> : IRepository<T> where T : BaseEntity
{
      private IDbContext _context;
      private IDbSet<T> _entities;

      protected virtual IDbSet<T> Entities
      {
          get
          {
              if (_entities == null)
                  _entities = _context.Set<T>();
              return _entities;
          }
      }

      public virtual void Insert(IEnumerable<T> entities, bool enableTrackChanges = true)
        {
            try
            {
                if (entities == null)
                    throw new ArgumentNullException("entities");

                if(!enableTrackChanges)
                {
                    this._context.AutoDetectChangesEnabled = false;
                }

                foreach (var entity in entities)
                    this.Entities.Add(entity);

                this._context.SaveChanges();
            }
            catch (DbEntityValidationException dbEx)
            {
                throw new Exception(GetFullErrorText(dbEx), dbEx);
            }
            finally
            {
                if (!this._context.AutoDetectChangesEnabled)
                    this._context.AutoDetectChangesEnabled = true;
            }
        }
}
PixelDev
  • 273
  • 2
  • 11
  • Your description of the issue is a bit light. From which line of code is the exception coming from? Is it the SaveChange? Could you maybe show the loop in your question? – Gimly Aug 23 '17 at 07:32
  • @Gimly yes on SaveChanges where i get this error. – PixelDev Aug 23 '17 at 07:34
  • on context.SaveChanges(); when loop is coming on this after saving 30000 of records then i get error – PixelDev Aug 23 '17 at 07:35
  • How much ram you have is irrelevant. Read [It's the address space stupid](https://blogs.msdn.microsoft.com/oldnewthing/20130628-00/?p=3963) (which may sound rude if you're not aware that it's wordplay based on a famous quote) – Damien_The_Unbeliever Aug 23 '17 at 07:44
  • Where did you kept your savechanges()...is it in loop or outside loop? – LifeOfPi Aug 23 '17 at 07:45
  • @Prathyush it's outside of loop – PixelDev Aug 23 '17 at 07:47
  • EfRepository is a class from nopcommerce? Could you show how you use that class when inserting the data? – m4ttsson Aug 23 '17 at 09:43
  • @m4ttsson as i was updated my code and i just call this "Insert" method from service using "IRepository" with instance and call this insert method like this "myRepository.Insert(myclassData, false);" – PixelDev Aug 23 '17 at 09:51
  • Maybe you should create an issue on nopcommerce github repo, since it seems to be that code that can't handle too much data. Might get more help there. – m4ttsson Aug 23 '17 at 10:07
  • Otherwise you could try to split your data and recreate myrepository instance for every 5000 rows or something like that – m4ttsson Aug 23 '17 at 10:09
  • @m4ttsson i am following your steps and finding solution on based your answer hope it will help me. – PixelDev Aug 23 '17 at 10:18

1 Answers1

4

You need to recreate the context in order to avoid outofmemoryexception. The memory will increase until entity framework can't handle it and then the exception is thrown. It is a memory limitation in entity framework so it won't help to run on an even better computer.

This should work:

if(Counter % 500 == 0)
{
    _context.SaveChanges();
    _context = new ....();
}

Also see this for some more help on inserting many rows with EF. Fastest Way of Inserting in Entity Framework

Edit: I apologize for being unclear and not citing sources. The limitation of an object in .NET is 2GB, arrays can be bigger on 64bit machines but an EF context cannot be bigger than 2GB. And when using an EF context continuously the memory usage may increase rapidly until the limit is reached. To free memory it is therefore best to renew the context after a while when inserting many rows of data. So the limit is on .NET, not on EF as I mistakenly said before.

About EF context: https://msdn.microsoft.com/en-us/library/jj729737(v=vs.113).aspx

How to get >2gb arrays (also says that other objects are unchanged) https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/gcallowverylargeobjects-element

Old longer source about 2GB limit and larger arrays: https://blogs.msdn.microsoft.com/joshwil/2005/08/10/bigarrayt-getting-around-the-2gb-array-size-limit/

m4ttsson
  • 203
  • 2
  • 8
  • Thanks for your answer i will try this and let you know because it's take time. – PixelDev Aug 23 '17 at 07:43
  • in this here my context is this private readonly IDbContext _context; In IDbContext it's an interface – PixelDev Aug 23 '17 at 07:49
  • Can you help me to using this i am using nopcommerse for this – PixelDev Aug 23 '17 at 07:50
  • How is the IDbContext created/inserted into the class that has the _context? – m4ttsson Aug 23 '17 at 07:55
  • 1
    _"It is a memory limitation in entity framework"_ - that sounds like voodoo programming. Don't suggest fixes if you don't understand the problem. – CodeCaster Aug 23 '17 at 07:56
  • @m4ttsson, i am using this in public partial class EfRepository : IRepository where T : BaseEntity – PixelDev Aug 23 '17 at 07:57
  • @CodeCaster I've had this exact problem before and recreating the context usually works. I'm looking for the source for my statement about EF, will post it when I find it. – m4ttsson Aug 23 '17 at 07:58
  • @CodeCaster Then if you are a great programmer then please suggest me how i can change this limitation in entity framework. or give another solution. Otherwise ignore this question please. – PixelDev Aug 23 '17 at 07:59
  • @Vishal, Can you change _context to be not readonly and do _context = new EfRepository() or something similar? – m4ttsson Aug 23 '17 at 07:59
  • @Vishal how good of a programmer I am is irrelevant here. I'm explaining why [voodoo programming](https://en.wikipedia.org/wiki/Voodoo_programming), or _"getting a program to produce desired output by using guesses, trial-and-error, cookbooks, copy-pasting from online resources"_, is not a good way of answering questions. An answer on Stack Overflow must explain the problem and its solution, not just say "try this, this library is buggy and this works for me". If you don't understand that difference, then that's your problem. – CodeCaster Aug 23 '17 at 08:03
  • @m4ttsson, i am using public partial class EfRepository : IRepository where T : BaseEntity this so when i creating this _context = new EfRepository() it is give error "required 1 type argument." – PixelDev Aug 23 '17 at 08:07
  • @CodeCaster please as when you are a beginner then also you are face same problem then why you are behaving like this. I am also a beginner and if i am not understand what is the issue and why i am wrong then. I asked a question and developers are helping for this where i am wrong not answering like you. If you are unable to help me and suggest where i am wrong then please ignore this question. – PixelDev Aug 23 '17 at 08:28
  • @Vishal I did help you. In the duplicates there's enough explanations and solutions to explain how to resolve this. – CodeCaster Aug 23 '17 at 08:45
  • @CodeCaster Yes i check that but and tried all that things but still it's not resolve. as i edit my question again please check it i think it is help you to better to understand my question and if still there have any issue in my question then again let me know i provide more details about this, – PixelDev Aug 23 '17 at 08:52