web-dev-qa-db-fra.com

Comment effacer les entités suivies dans le cadre des entités

J'exécute un code de correction qui parcourt un grand nombre d'entités, sa vitesse diminue, car le nombre d'entités suivies dans le contexte augmente à chaque itération. Cela peut prendre longtemps et enregistrer les modifications à la fin. de chaque itération. Chaque itération est indépendante et ne change pas les entités chargées précédemment. 

Je sais que je peux désactiver le suivi des modifications, mais je ne le souhaite pas, car il ne s'agit pas d'un code d'insertion en bloc, mais du chargement des entités et du calcul de certaines choses. Si les nombres ne sont pas corrects, définissez les nouveaux numéros et mettez à jour/supprimer/créer certaines entités supplémentaires. Je sais que je peux créer un nouveau DbContext pour chaque itération et que cela fonctionnerait probablement plus rapidement que de tout faire dans le même cas, mais je pense qu'il pourrait y avoir un meilleur moyen. 

Alors la question est; Existe-t-il un moyen de supprimer les entités précédemment chargées dans le contexte de base de données?

36
hazimdikenli

Vous pouvez ajouter une méthode à votre DbContext ou une méthode d'extension qui utilise ChangeTracker pour détacher toutes les entités ajoutées, modifiées et supprimées:

public void DetachAllEntities()
{
    var changedEntriesCopy = this.ChangeTracker.Entries()
        .Where(e => e.State == EntityState.Added ||
                    e.State == EntityState.Modified ||
                    e.State == EntityState.Deleted)
        .ToList();

    foreach (var entry in changedEntriesCopy)
        entry.State = EntityState.Detached;
}
59
David Sherret

1. Possibilité: détachez l'entrée

dbContext.Entry(entity).State = EntityState.Detached;

Lorsque vous détachez l'entrée, le suivi des modifications cesse de la suivre (et devrait améliorer les performances).

Voir: http://msdn.Microsoft.com/de-de/library/system.data.entitystate(v=vs.110).aspx

2. Possibilité: travailler avec votre propre champ Status + contextes déconnectés

Peut-être souhaitez-vous contrôler le statut de votre entité de manière indépendante pour pouvoir utiliser des graphiques déconnectés. Ajoutez une propriété pour le statut de l'entité et transformez ce statut en dbContext.Entry(entity).State lors de l'exécution d'opérations (utilisez un référentiel pour le faire)

public class Foo
{
    public EntityStatus EntityStatus { get; set; }
}

public enum EntityStatus
{
    Unmodified,
    Modified,
    Added
}

Voir le lien suivant pour un exemple: https://www.safaribooksonline.com/library/view/programming-entity-framework/9781449331825/ch04s06.html

11
road242

Je viens de rencontrer ce problème et je suis finalement tombé sur une meilleure solution pour ceux qui utilisent l'injection de dépendance .NET Core typique. Vous pouvez utiliser un DbContext défini pour chaque opération. Cela réinitialisera DbContext.ChangeTracker de sorte que SaveChangesAsync() ne s'enlise pas dans la vérification des entités des itérations précédentes. Voici un exemple de méthode ASP.NET Core Controller:

    /// <summary>
    /// An endpoint that processes a batch of records.
    /// </summary>
    /// <param name="provider">The service provider to create scoped DbContexts.
    /// This is injected by DI per the FromServices attribute.</param>
    /// <param name="records">The batch of records.</param>
    public async Task<IActionResult> PostRecords(
        [FromServices] IServiceProvider provider,
        Record[] records)
    {
        // The service scope factory is used to create a scope per iteration
        var serviceScopeFactory =
            provider.GetRequiredService<IServiceScopeFactory>();

        foreach (var record in records)
        {
            // At the end of the using block, scope.Dispose() will be called,
            // release the DbContext so it can be disposed/reset
            using (var scope = serviceScopeFactory.CreateScope())
            {
                var context = scope.ServiceProvider.GetService<MainDbContext>();

                // Query and modify database records as needed

                await context.SaveChangesAsync();
            }
        }

        return Ok();
    }

Étant donné que les projets ASP.NET Core utilisent généralement DbContextPool, cela ne crée ni ne détruit même pas les objets DbContext. (Au cas où cela vous intéresserait, DbContextPool appelle en fait DbContext.ResetState() et DbContext.Resurrect(), mais je ne recommanderais pas de les appeler directement à partir de votre code, car ils seront probablement modifiés dans les prochaines versions.) https://github.com/ aspnet/EntityFrameworkCore/blob/v2.2.1/src/EFCore/Internal/DbContextPool.cs # L157

1
Matt