Faster way to save multiple entities with Entityframework

Asked

Viewed 574 times

6

I have a performance problem in one method, in addition to causing the full use of the CPU server that method takes a long time to run.

 internal async void NotificacaoIosTodos(string titulo, int posicao, int unidadeId)
    {
        try
        {
            _contexto.Configuration.AutoDetectChangesEnabled = false;
            _contexto.Configuration.ValidateOnSaveEnabled = false;

            var unidade =  _contexto.Unidade.FirstOrDefault(l => l.UnidadeId == unidadeId);
           var pessoas =  _contexto.PessoaUnidade.Include(l => l.Pessoa)
                .Where(l => l.Pessoa.Dispositivo == (int)enumDispositivo.Ios && l.UnidadeId == unidadeId)
                .ToList();
            var quantidadeAdicionada = 0;

            Notificacao notificacao = new Notificacao { Posicao = posicao };
            _contexto.Notificacao.Add(notificacao);

            foreach (PessoaUnidade pessoa in pessoas)
            {

                PessoaNotificacao pessoaNotificacao = new PessoaNotificacao
                {
                    Visualizado = false,
                    PessoaUnidade = pessoa,
                    Notificacao = notificacao
                };
                _contexto.PessoaNotificacao.Add(pessoaNotificacao);



            }


        await _contexto.SaveChangesAsync();

        }
        catch (Exception e)
        {
             throw;
        }

    }

The problem is that I have to insert approximately 1700 records at once, when I run the method dbContexto.SaveChanges() or dbContext.SaveChangesAsync(), takes more than 10 minutes to finish, causing timeout.

I searched the subject and found some options as for example this response from Stackoverflow in English, I left saving 400 in 400 records and created a new instance of dbContext , but it did not help the performace, it still took more than 10 minutes.

I would like to know how to make this method run faster, I have no idea where to go, would be happy with any hint or explanations.

  • 1

    Related: https://answall.com/questions/133553/howto run o-sqlbulkcopy

  • 1

    Related: https://answall.com/questions/92884/erro-ao-insertion-dados-no-banco-ef-6

2 answers

7

There are 4 options, I would choose the 4:

1 - Using Bulk Insert There is an Extensions for Entity that promises a good performance improvement http://entityframework-extensions.net/overview

2 - Do not use Entityframework for this operation You could use Dapper or Storedprocedure - (I refer to Dapper)

3 - Change the implementation Instead of adding notification to all users you could add a notification with a FLAG indicating that it is for all, when the user 'request' the notification would check if he already read the notification. Implementation Thinking of relational database would be created 3 tables.

Notifications to store information of notifications and users who must receive the notification would put notification types, such as: ALL (notify all users), GROUP(specific group defined in business rules), USER (a single user).

Notified users - store which notifications were delivered. When the user receives the notification it would generate a record in this table stating that the notification X was delivered to the user Y. Thus it would be able to know what notification a particular user should receive through a query in all notifications that are in groups that the user participates and that do not exist in the table of notified users.

4 - Using Notifications Hub or Signalr As it seems you are wanting to create Pushnotification it would be more appropriate if you implement with Signalr or using the Azure service https://azure.microsoft.com/en-us/services/notification-hubs/

  • I even use a notification system, OneSignal , but we had problems with delivering additional data when the application is in the background, so this routine was done to save some information, such as menu position and if it has already been viewed, I create only one notification and make the call to each client to check if this viewed, I did not understand how I would make the 3 option. I will try option 1 and do some testing to see what the gain would be, I will do tests with the second option as well and check the possibility of changing the OneSignal for one of the cited. Thank you!

  • 1
  • 1

    The Bulk Insert solved my problem, worth resaltar that the commands _contexto.Configuration.AutoDetectChangesEnabled = false; and _contexto.Configuration.ValidateOnSaveEnabled = false;also make a good difference in performance. Thank you so much for having responded helped me a lot.

  • As told by @Edvaldosilva Bulk Insert is paid and after 1 month of use it will release an exception for you to buy the full version.

2


Sqlbulkcopy - very fast!

I recommend using, see here an example: Sql Bulk Insert for Entity Framework 6

Resource reference: Sqlbulkcopy Class

To improve overall performance

Lazy Load

_contexto.Configuration.ProxyCreationEnabled = true;
_contexto.Configuration.LazyLoadingEnabled = true;

Properties that refer to another object must be declared as virtual:

public partial class Pessoa
{
   public virtual ICollection<Contato> Contatos { get; set; }
}

Reference: Lazy Loading

  • 2

    I only made the edition of your reply, because, the site follows a pattern, any doubts follow the advanced help

  • 1

    @Virgilionovic thank you!

  • Explain to me how the Lazy Load may be faster than the Eager Load?

  • @Tobiasmesquita because you only carry what you need. Ex.: Entity A has one or more relationships one for many with other entities, but for a certain view I only need the data from Entity A, Why bring all relationships? So with Lazy Load I can control that, I only carry what I will use.

  • I’m studying this example you mentioned, but I’m having a little trouble understanding how Sqlbulkcopy works. the rest I had already done (Lazy Load, and the removal of the checks).

  • Finally I ended up using Sqlbulkcopy, so I decided to accept your answer, it was good if you add an example of use, I will try to edit when you have some time.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.