none
Upsert/bulkcopy/Merge RRS feed

  • Pregunta

  • Hola a todos/as

    Tengo una duda a ver si me la podéis resolver. 

    Tengo el siguiente método:

    private void addOrUpdateAccount(Account account, IntegrationDbContext IntegrationContext)
            {
                var existingAccount = IntegrationContext.Accounts.Where(a => a.ClientNumber == account.ClientNumber).FirstOrDefault();
                
    
    if (existingAccount == null)
    {
     // Create Account
        account.Id = Guid.NewGuid();                
        account.CheckedFrom = DateTime.UtcNow;
        account.UpdatedFrom = DateTime.UtcNow;
        IntegrationContext.Accounts.Add(account);
    }
    else
    {
    // Update Account
                    
       existingAccount.CheckedFrom = DateTime.UtcNow;
       existingAccount.UpdatedFrom = DateTime.UtcNow;
       existingAccount.FiscalName = account.FiscalName;
       
       (......)
    
    }                

    El problema es que al ir registro por registro, es extremadamente lento. Necesito mover más de 2000 registros al día, con lo cual, esta opción no la veo viable.

    Habría alguna forma de hacer un bulkcopy/upsert o algo parecido con EF7??

    Muchas gracias por adelantado.

    Saludos!

    lunes, 9 de mayo de 2016 10:23

Todas las respuestas

  • Asegúrate de que a cada llamada a ese método vuelves a hacer un "new" del IntegrationDbContext y luego un Dispose (en lugar de crear una única instancia y llamar todas las veces al procedimiento con la misma instancia). Por ejemplo, llamándolo dentro de un "using". Esto acelerará muchísimo el funcionamiento, porque de esta manera se limpia la lista interna que mantiene el DbContext para hacer el "tracking" de todos los objetos. Al no hacer ese seguimiento interno, se limitará a enviar al servidor un Select seguido de un Insert o Update. Son 4000 sentencias para tus 2000 registros. Se deberían ejecutar en una fracción de segundo, si la base de datos está bien configurada.
    lunes, 9 de mayo de 2016 16:48
  • Hola Alberto. 

    Muchas gracias por tu respuesta.

    Te refieres a algo como ésto??

    while (continueJob) { var newClient = getNextNewClient(lastCreatedDateChecked.Value); if (newClient == null) { continueJob = false; } else { var IntegrationContext1 = IntegrationContext; (. . . ) addOrUpdateAccount(newAccount, IntegrationContext1);

    ( . . . )

    IntegrationContext1.Dispose(); } (. . .) while (continueJob) { var modifiedClient = getNextModifiedClient(lastUpdatedDateChecked.Value); if (modifiedClient == null) { continueJob = false; } else { var IntegrationContext2 = IntegrationContext; (. . .) addOrUpdateAccount(newAccount, IntegrationContext2);

    ( . . .)

    IntegrationContext2.Dispose();

    } ( . . .)

    OK. Lo pruebo y te digo.

    Saludos!

    martes, 10 de mayo de 2016 8:24
  • Está un poco liado, no lo sigo bien, pero tiene pinta de que no va a funcionar. Estás simplemente copiando el IntegrationContext a una variable. Es un tipo-referencia, por lo que sigues usando la misma instancia, y por lo tanto no deshaces el tracking. Y además has metido una llamada al Dispose que cerrará todas las copias, con lo que te producirá errores a partir de ese punto.

    Mi idea era más bien algo parecido a esto:

    private void addOrUpdateAccount(Account account)
    {
        using (IntegrationDbContext IntegrationContext = new IntegrationDbContext())
        {
            //Aquí va todo lo que antes tenías dentro del método addOrUpdateAccount
        }
    }   

    martes, 10 de mayo de 2016 10:11
  • Hola Alberto!

    Gracias por responder. Creo que ya pillé lo que dices. Sería algo como ésto:

    private void addOrUpdateAccount(Account account)
    {
        using (IntegrationDbContext IntegrationContext = new IntegrationDbContext())
         {
            var existingAccount = IntegrationContext.Accounts.Where(a => a.ClientNumber == account.ClientNumber).FirstOrDefault();
    
    if (existingAccount == null)
                    {
                        // Create Account
                        account.Id = Guid.NewGuid();
                        account.CheckedFrom = DateTime.UtcNow;
                        account.UpdatedFrom = DateTime.UtcNow;
                        IntegrationContext.Accounts.Add(account);
                    }
                    else
                    {
                        // Update Account
    
                        existingAccount.CheckedFrom = DateTime.UtcNow;
                        existingAccount.UpdatedFrom = DateTime.UtcNow;
                        existingAccount.FiscalName = account.FiscalName;
                     }
    	( . . .)
    	}
    	IntegrationContext.dispose()
    }

    Es correcto lo que interpreto??

    Muchas gracias!

    • Editado CrepuX martes, 10 de mayo de 2016 12:34
    martes, 10 de mayo de 2016 12:33