3
votes

Fractionner une liste en morceaux - C #

J'ai une liste qui comprend environ 1 000 000 d'enregistrements. Et j'utilise EF pour l'insérer dans la base de données. Comme cela prend trop de temps, je dois diviser cette liste en blocs de 100 enregistrements et l'enregistrer.

Comment puis-je faire cela?

await dbCont.People.AddAsync(peoples);
await dbCont.Savechanges();

La liste des personnes ici contient 1 000 000 d'enregistrements. Et au lieu de tout enregistrer en même temps (ralentit l'insertion), je dois insérer environ 100 enregistrements à la fois. Comment puis-je faire cela?


9 commentaires

Jetez un œil à linq Skip et Take : docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/li‌ nq /…


@TomJohn Connaissez-vous une méthode où je pourrais insérer du volume en utilisant EF?


Vous savez que cela créera probablement 10.000 transactions, si l'une d'entre elles échoue, les transactions précédentes ont déjà été validées?


@ LasseVågsætherKarlsen Comment pensez-vous que je pourrais surmonter mon problème?


Jetez un œil à ce fil de discussion stackoverflow.com/questions/11463734/... - cela pourrait aider.


Conservez le code tel quel ou essayez de suivre une véritable solution d'insertion en bloc. Le problème est que le framework d'entité fait beaucoup de travail dans les coulisses et l'insertion en masse peut contourner cela, de sorte qu'il n'est peut-être pas possible de l'utiliser.


@ LasseVågsætherKarlsen Y a-t-il des packages / framework Nuget que vous savez que je pourrais utiliser?


Un gros problème de performances est que pendant EF génère un INSERT pour chaque objet lors de l'appel de SaveChanges. Il existe une extensibilité d'insertion en bloc dans la bibliothèque EF Core, mais ce n'est pas bon marché.


Est-ce que cela répond à votre question? Fractionner une liste en listes plus petites de taille N


3 Réponses :


0
votes

Vous pouvez le faire comme ceci:

var batchSize = 100;
var processed = 0;
var hasNextBatch = true;

while(hasNextBatch) 
{
    var batch = peoples.Skip(processed).Take(batch).ToList();
    await dbCont.People.AddAsync(batch);
    await dbCont.Savechanges();
    processed += batch.count;
    hasNextBatch = batch.Count == batchSize;
}

mais vous devrez considérer que lorsqu'une insertion de lot échoue, les lots précédents sont déjà validés.


0 commentaires

1
votes

Vous pouvez utiliser la méthode d'extension Batch du bibliothèque MoreLinq : regroupe la séquence source dans des seaux dimensionnés.

1, 2, 3, 4, 5, 6, 7, 8, 9, 10
11, 12, 13, 14, 15, 16, 17, 18, 19, 20
21, 22, 23, 24, 25

Output

var list = new List<int>(Enumerable.Range(1, 25));
var buckets = list.Batch(size: 10);
foreach (var bucket in buckets)
{
    Console.WriteLine(String.Join(", ", bucket));
}


0 commentaires

0
votes

J'ai essayé d'insérer des blocs dans EF par le passé, mais c'est lent à cause du suivi des entités. Bien sûr, vous pouvez désactiver le suivi des entités, mais il vaut mieux utiliser SqlBulkCopy pour insérer en bloc. Voici un bon article Insertion en masse de données dans SQL Server .


2 commentaires

Puis-je utiliser quelque chose qui va avec EF?


EF est mauvais pour l'insertion en masse, au cas où vous souhaiteriez une insertion en masse à l'aide d'entités, vous pouvez utiliser Dapper: dapper-tutorial. net / insertion groupée