La manière la plus rapide d'insérer dans le cadre de L'entité
je suis à la recherche du moyen le plus rapide d'insérer dans le cadre de L'entité.
je pose cette question à cause du scénario où vous avez un Scope de transaction active et l'insertion est énorme (4000+). Il peut durer plus de 10 minutes (délai d'attente par défaut des transactions), ce qui entraînera une transaction incomplète.
25 réponses
À votre remarque dans les commentaires à votre question:
"...SavingChanges ( pour chaque dossier )..."
C'est la pire chose à faire! Appeler SaveChanges()
pour chaque record ralentit considérablement les inserts en vrac. Je voudrais faire quelques tests simples qui amélioreront très probablement la performance:
- Appel
SaveChanges()
une fois, après TOUS les records. - Appel
SaveChanges()
après par exemple 100 enregistrements. - appeler
SaveChanges()
après par exemple 100 enregistrements et disposer le contexte et en créer un nouveau. - Désactiver la détection de changement
pour les inserts en vrac je travaille et expérimente avec un modèle comme celui-ci:
using (TransactionScope scope = new TransactionScope())
{
MyDbContext context = null;
try
{
context = new MyDbContext();
context.Configuration.AutoDetectChangesEnabled = false;
int count = 0;
foreach (var entityToInsert in someCollectionOfEntitiesToInsert)
{
++count;
context = AddToContext(context, entityToInsert, count, 100, true);
}
context.SaveChanges();
}
finally
{
if (context != null)
context.Dispose();
}
scope.Complete();
}
private MyDbContext AddToContext(MyDbContext context,
Entity entity, int count, int commitCount, bool recreateContext)
{
context.Set<Entity>().Add(entity);
if (count % commitCount == 0)
{
context.SaveChanges();
if (recreateContext)
{
context.Dispose();
context = new MyDbContext();
context.Configuration.AutoDetectChangesEnabled = false;
}
}
return context;
}
j'ai un programme de test qui insère 560.000 entités (9 propriétés scalaires, no propriétés de navigation) dans le DB. Avec ce code, il fonctionne en moins de 3 minutes.
Pour la performance, il est important d'appeler SaveChanges()
après "plusieurs" dossiers ("beaucoup" autour de 100 ou 1000). Il améliore également les performances de disposer du contexte après SaveChanges et en créer un nouveau. Cela efface le contexte de toutes les entités, SaveChanges
ne fait pas cela, les entités sont toujours attachées au contexte dans l'état Unchanged
. C'est la taille croissante de l'attaché entités dans le contexte ce qui ralentit l'insertion pas à pas. Donc, il est utile de le vider après un certain temps.
voici quelques mesures pour mes 560.000 entités:
- commitCount = 1, recreateContext = false: nombre d'heures (C'est votre procédure actuelle)
- commitCount = 100, recreateContext = false: plus de 20 minutes 1519200920"
- commitCount = 1000, recreateContext = false: 242 sec
- commitCount = 10000, recreateContext= false: 202 sec
- commitCount = 100000, recreateContext= false: 199 sec
- commitCount = 1000000, recreateContext= false: out of memory exception
- commitCount = 1, recreateContext = true: plus de 10 minutes
- commitCount = 10, recreateContext = true: 241 sec
- commitCount = 100, recreateContext= true: 164 sec
- commitCount = 1000, recreateContext = true: 191 sec
Le comportement dans le premier test ci-dessus est que la performance est très non linéaire et diminue considérablement avec le temps. ("Plusieurs heures" est une estimation, Je n'ai jamais terminé ce test, je me suis arrêté à 50.000 entités après 20 minutes.) Ce comportement non linéaire n'est pas aussi significatif dans tous les autres essais.
cette combinaison augmente suffisamment la vitesse.
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
le moyen le plus rapide serait d'utiliser bulk insert extension , que j'ai développé.
il utilise SqlBulkCopy et custom datareader pour obtenir des performances max. En conséquence, il est plus de 20 fois plus rapide que l'utilisation régulière insert ou AddRange
l'usage est extrêmement simple
context.BulkInsert(hugeAmountOfEntities);
vous devriez regarder en utilisant le System.Data.SqlClient.SqlBulkCopy
pour cela. Voici la documentation , et bien sûr il ya beaucoup de tutoriels en ligne.
Désolé, je sais que vous cherchiez une réponse simple pour que EF fasse ce que vous voulez, mais les opérations en vrac ne sont pas vraiment ce que les ORMs sont censés faire.
Je suis D'accord avec Adam Rackis. SqlBulkCopy
est le moyen le plus rapide de transférer des enregistrements en vrac d'une source de données à une autre. J'ai utilisé ça pour copier des disques de 20K et ça a pris moins de 3 secondes. Regardez l'exemple ci-dessous.
public static void InsertIntoMembers(DataTable dataTable)
{
using (var connection = new SqlConnection(@"data source=;persist security info=True;user id=;password=;initial catalog=;MultipleActiveResultSets=True;App=EntityFramework"))
{
SqlTransaction transaction = null;
connection.Open();
try
{
transaction = connection.BeginTransaction();
using (var sqlBulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction))
{
sqlBulkCopy.DestinationTableName = "Members";
sqlBulkCopy.ColumnMappings.Add("Firstname", "Firstname");
sqlBulkCopy.ColumnMappings.Add("Lastname", "Lastname");
sqlBulkCopy.ColumnMappings.Add("DOB", "DOB");
sqlBulkCopy.ColumnMappings.Add("Gender", "Gender");
sqlBulkCopy.ColumnMappings.Add("Email", "Email");
sqlBulkCopy.ColumnMappings.Add("Address1", "Address1");
sqlBulkCopy.ColumnMappings.Add("Address2", "Address2");
sqlBulkCopy.ColumnMappings.Add("Address3", "Address3");
sqlBulkCopy.ColumnMappings.Add("Address4", "Address4");
sqlBulkCopy.ColumnMappings.Add("Postcode", "Postcode");
sqlBulkCopy.ColumnMappings.Add("MobileNumber", "MobileNumber");
sqlBulkCopy.ColumnMappings.Add("TelephoneNumber", "TelephoneNumber");
sqlBulkCopy.ColumnMappings.Add("Deleted", "Deleted");
sqlBulkCopy.WriteToServer(dataTable);
}
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
}
}
}
J'ai étudié la réponse de Slauma (ce qui est génial, merci pour l'idea man), et j'ai réduit la taille du lot jusqu'à ce que j'ai atteint la vitesse optimale. En regardant les résultats de la Slauma:
- commitCount = 1, recreateContext = true: more than 10 minutes
- commitCount = 10, recreateContext= true: 241 sec
- commitCount = 100, recreateContext= true: 164 sec
- commitCount = 1000, recreateContext = true: 191 sec
il est visible qu'il y a une augmentation de vitesse quand on passe de 1 à 10, et de 10 à 100, mais de 100 à 1000 en insérant la vitesse est de nouveau en baisse.
donc j'ai mis l'accent sur ce qui se passe quand vous réduisez la taille du lot de valeur quelque part entre 10 et 100, et voici mes résultats (j'utilise des contenus de ligne différents, donc mes temps sont de valeur différente):
Quantity | Batch size | Interval
1000 1 3
10000 1 34
100000 1 368
1000 5 1
10000 5 12
100000 5 133
1000 10 1
10000 10 11
100000 10 101
1000 20 1
10000 20 9
100000 20 92
1000 27 0
10000 27 9
100000 27 92
1000 30 0
10000 30 9
100000 30 92
1000 35 1
10000 35 9
100000 35 94
1000 50 1
10000 50 10
100000 50 106
1000 100 1
10000 100 14
100000 100 141
basé sur mes résultats, optimum réel est d'environ la valeur de 30 pour la taille du lot. C'est moins de 10 et 100. Le problème, c'est que je ne sais pas pourquoi 30 est optimal, et je n'aurais pas pu trouver d'explication logique.
je recommande cet article sur la façon de faire des inserts en vrac en utilisant EF.
Entity Framework et lente des Insertions
il explore ces domaines et compare la performance:
- EF par défaut (57 minutes pour compléter l'ajout de 30 000 enregistrements)
- remplacé par ADO.NET Code (25 seconds for those same 30,000)
- Contexte Bloat-garder le graphe de contexte actif petit en utilisant un nouveau contexte pour chaque unité de travail (même 30,000 inserts prennent 33 secondes)
- Large Lists-Turn off AutoDetectChangesEnabled (ramène le temps à environ 20 secondes)
- par lot (jusqu'à 16 secondes)
- DbTable.AddRange() - (performance est dans la 12 de gamme)
comme d'autres personnes ont dit SqlBulkCopy est la façon de le faire si vous voulez vraiment bonne performance d'insertion.
c'est un peu encombrant à mettre en œuvre, mais il y a des bibliothèques qui peuvent vous aider avec cela. Il ya quelques-uns là-bas, mais je vais shamelesslyplug ma propre bibliothèque cette fois: https://github.com/MikaelEliasson/EntityFramework.Utilities#batch-insert-entities
le seul code dont vous avez besoin est:
using (var db = new YourDbContext())
{
EFBatchOperation.For(db, db.BlogPosts).InsertAll(list);
}
c'est beaucoup plus rapide? Très difficile à dire car il dépend de tant de facteurs, la performance de l'ordinateur, le réseau, la taille de l'objet, etc. Les tests de performance que j'ai faits suggèrent que les entités 25k peuvent être insérées à environ 10s le standard way sur localhost si vous optimisez votre configuration EF comme mentionné dans les autres réponses. Avec EFUtilities qui prend environ 300ms. Encore plus intéressant est que j'ai sauvé environ 3 millions d'entités dans moins de 15 secondes en utilisant cette méthode, avec une moyenne d'environ 200K entités par seconde.
le seul problème est bien sûr si vous avez besoin d'insérer des données releated. Cela peut être fait efficacement dans sql server en utilisant la méthode ci-dessus, mais cela exige que vous ayez une stratégie de génération D'Id qui vous permette de générer des id dans l'app-code pour le parent afin que vous puissiez définir les clés étrangères. Cela peut être fait en utilisant des GUIDs ou quelque chose comme génération HiLo id.
"151910920 contextuel" créer des problèmes si les entités Add()
s'appuyer sur d'autres préchargé entités (par exemple, les propriétés de navigation) dans le contexte
j'utilise un concept similaire pour garder mon contexte petit pour atteindre la même performance
mais au lieu de Dispose()
le contexte et recréer, je détache simplement les entités qui déjà SaveChanges()
public void AddAndSave<TEntity>(List<TEntity> entities) where TEntity : class {
const int CommitCount = 1000; //set your own best performance number here
int currentCount = 0;
while (currentCount < entities.Count())
{
//make sure it don't commit more than the entities you have
int commitCount = CommitCount;
if ((entities.Count - currentCount) < commitCount)
commitCount = entities.Count - currentCount;
//e.g. Add entities [ i = 0 to 999, 1000 to 1999, ... , n to n+999... ] to conext
for (int i = currentCount; i < (currentCount + commitCount); i++)
_context.Entry(entities[i]).State = System.Data.EntityState.Added;
//same as calling _context.Set<TEntity>().Add(entities[i]);
//commit entities[n to n+999] to database
_context.SaveChanges();
//detach all entities in the context that committed to database
//so it won't overload the context
for (int i = currentCount; i < (currentCount + commitCount); i++)
_context.Entry(entities[i]).State = System.Data.EntityState.Detached;
currentCount += commitCount;
} }
enveloppez-le avec try catch et TrasactionScope()
si vous besoin,
ne pas les montrer ici pour garder le code propre
essayez d'utiliser un procédure stockée qui obtiendra un XML des données que vous voulez insérer.
j'ai fait une extension générique de l'exemple de @Slauma ci-dessus;
public static class DataExtensions
{
public static DbContext AddToContext<T>(this DbContext context, object entity, int count, int commitCount, bool recreateContext, Func<DbContext> contextCreator)
{
context.Set(typeof(T)).Add((T)entity);
if (count % commitCount == 0)
{
context.SaveChanges();
if (recreateContext)
{
context.Dispose();
context = contextCreator.Invoke();
context.Configuration.AutoDetectChangesEnabled = false;
}
}
return context;
}
}
Utilisation:
public void AddEntities(List<YourEntity> entities)
{
using (var transactionScope = new TransactionScope())
{
DbContext context = new YourContext();
int count = 0;
foreach (var entity in entities)
{
++count;
context = context.AddToContext<TenancyNote>(entity, count, 100, true,
() => new YourContext());
}
context.SaveChanges();
transactionScope.Complete();
}
}
je sais que c'est une très vieille question, mais un gars ici a dit que développé une méthode d'extension pour utiliser insert en vrac avec EF, et quand j'ai vérifié, j'ai découvert que la bibliothèque coûte 599 $aujourd'hui (pour un développeur). Peut-être que cela a du sens pour l'ensemble de la bibliothèque, mais pour le seul encart en vrac c'est trop.
Voici une méthode d'extension très simple que j'ai faite. Je l'utilise sur la paire avec la base de données d'abord (ne pas testé avec le code d'abord, mais je pense que cela fonctionne la même chose). Changer YourEntities
avec le nom de votre contexte:
public partial class YourEntities : DbContext
{
public async Task BulkInsertAllAsync<T>(IEnumerable<T> entities)
{
using (var conn = new SqlConnection(Database.Connection.ConnectionString))
{
conn.Open();
Type t = typeof(T);
var bulkCopy = new SqlBulkCopy(conn)
{
DestinationTableName = GetTableName(t)
};
var table = new DataTable();
var properties = t.GetProperties().Where(p => p.PropertyType.IsValueType || p.PropertyType == typeof(string));
foreach (var property in properties)
{
Type propertyType = property.PropertyType;
if (propertyType.IsGenericType &&
propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
propertyType = Nullable.GetUnderlyingType(propertyType);
}
table.Columns.Add(new DataColumn(property.Name, propertyType));
}
foreach (var entity in entities)
{
table.Rows.Add(
properties.Select(property => property.GetValue(entity, null) ?? DBNull.Value).ToArray());
}
bulkCopy.BulkCopyTimeout = 0;
await bulkCopy.WriteToServerAsync(table);
}
}
public void BulkInsertAll<T>(IEnumerable<T> entities)
{
using (var conn = new SqlConnection(Database.Connection.ConnectionString))
{
conn.Open();
Type t = typeof(T);
var bulkCopy = new SqlBulkCopy(conn)
{
DestinationTableName = GetTableName(t)
};
var table = new DataTable();
var properties = t.GetProperties().Where(p => p.PropertyType.IsValueType || p.PropertyType == typeof(string));
foreach (var property in properties)
{
Type propertyType = property.PropertyType;
if (propertyType.IsGenericType &&
propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
propertyType = Nullable.GetUnderlyingType(propertyType);
}
table.Columns.Add(new DataColumn(property.Name, propertyType));
}
foreach (var entity in entities)
{
table.Rows.Add(
properties.Select(property => property.GetValue(entity, null) ?? DBNull.Value).ToArray());
}
bulkCopy.BulkCopyTimeout = 0;
bulkCopy.WriteToServer(table);
}
}
public string GetTableName(Type type)
{
var metadata = ((IObjectContextAdapter)this).ObjectContext.MetadataWorkspace;
var objectItemCollection = ((ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace));
var entityType = metadata
.GetItems<EntityType>(DataSpace.OSpace)
.Single(e => objectItemCollection.GetClrType(e) == type);
var entitySet = metadata
.GetItems<EntityContainer>(DataSpace.CSpace)
.Single()
.EntitySets
.Single(s => s.ElementType.Name == entityType.Name);
var mapping = metadata.GetItems<EntityContainerMapping>(DataSpace.CSSpace)
.Single()
.EntitySetMappings
.Single(s => s.EntitySet == entitySet);
var table = mapping
.EntityTypeMappings.Single()
.Fragments.Single()
.StoreEntitySet;
return (string)table.MetadataProperties["Table"].Value ?? table.Name;
}
}
vous pouvez l'utiliser contre n'importe quelle collection qui hérite de IEnumerable
, comme cela:
await context.BulkInsertAllAsync(items);
je suis à la recherche du moyen le plus rapide d'insérer dans le cadre de L'entité
il y a des bibliothèques tierces supportant des encarts en vrac disponibles:
- Z. Entityfram Framework.Extensions ( Recommandé )
- EFUtilities
- Entityfram Framework.BulkInsert
Voir: Entity Framework Bulk Insérer bibliothèque
soyez prudent lorsque vous choisissez une bibliothèque d'inserts en vrac. Seule Entity Framework Extensions supporte toutes sortes d'associations et d'héritages et c'est la seule qui est encore supportée.
Disclaimer :je suis le propriétaire de Entity Framework Extensions
cette bibliothèque vous permet d'effectuer tous les opérations dont vous avez besoin pour vos scénarios:
- SaveChanges En Vrac
- Vrac Insérer
- En Vrac Supprimer
- Mise À Jour En Bloc
- Fusion En Vrac
exemple
// Easy to use
context.BulkSaveChanges();
// Easy to customize
context.BulkSaveChanges(bulk => bulk.BatchSize = 100);
// Perform Bulk Operations
context.BulkDelete(customers);
context.BulkInsert(customers);
context.BulkUpdate(customers);
// Customize Primary Key
context.BulkMerge(customers, operation => {
operation.ColumnPrimaryKeyExpression =
customer => customer.Code;
});
à ma connaissance il y a no BulkInsert
dans EntityFramework
pour augmenter la performance des énormes inserts.
dans ce scénario, vous pouvez aller avec SqlBulkCopy dans ADO.net
pour résoudre votre problème
Voici une comparaison de performance entre l'utilisation D'Entity Framework et L'utilisation de SqlBulkCopy class sur un exemple réaliste: Comment insérer des objets complexes dans la base de données SQL Server
comme d'autres l'ont déjà souligné, les ORM ne sont pas destinés à être utilisés dans les opérations en vrac. Ils offrent de la flexibilité, la séparation des préoccupations et d'autres avantages, mais les opérations en vrac (sauf la lecture en vrac) ne sont pas l'un d'entre eux.
une autre option est D'utiliser des SqlBulkTools disponibles chez Nuget. Il est très facile à utiliser et a quelques traits puissants.
exemple:
var bulk = new BulkOperations();
var books = GetBooks();
using (TransactionScope trans = new TransactionScope())
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager
.ConnectionStrings["SqlBulkToolsTest"].ConnectionString))
{
bulk.Setup<Book>()
.ForCollection(books)
.WithTable("Books")
.AddAllColumns()
.BulkInsert()
.Commit(conn);
}
trans.Complete();
}
Voir la documentation pour plus d'exemples et d'utilisation avancée. Avertissement: je suis l'auteur de cette bibliothèque et de toutes les vues sont de ma propre opinion.
utiliser SqlBulkCopy
:
void BulkInsert(GpsReceiverTrack[] gpsReceiverTracks)
{
if (gpsReceiverTracks == null)
{
throw new ArgumentNullException(nameof(gpsReceiverTracks));
}
DataTable dataTable = new DataTable("GpsReceiverTracks");
dataTable.Columns.Add("ID", typeof(int));
dataTable.Columns.Add("DownloadedTrackID", typeof(int));
dataTable.Columns.Add("Time", typeof(TimeSpan));
dataTable.Columns.Add("Latitude", typeof(double));
dataTable.Columns.Add("Longitude", typeof(double));
dataTable.Columns.Add("Altitude", typeof(double));
for (int i = 0; i < gpsReceiverTracks.Length; i++)
{
dataTable.Rows.Add
(
new object[]
{
gpsReceiverTracks[i].ID,
gpsReceiverTracks[i].DownloadedTrackID,
gpsReceiverTracks[i].Time,
gpsReceiverTracks[i].Latitude,
gpsReceiverTracks[i].Longitude,
gpsReceiverTracks[i].Altitude
}
);
}
string connectionString = (new TeamTrackerEntities()).Database.Connection.ConnectionString;
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
using (var sqlBulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction))
{
sqlBulkCopy.DestinationTableName = dataTable.TableName;
foreach (DataColumn column in dataTable.Columns)
{
sqlBulkCopy.ColumnMappings.Add(column.ColumnName, column.ColumnName);
}
sqlBulkCopy.WriteToServer(dataTable);
}
transaction.Commit();
}
}
return;
}
l'Un des moyens les plus rapides pour enregistrer une liste vous devez appliquer le code suivant
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
AutoDetectChangesEnabled = false
Add, AddRange & SaveChanges: ne détecte pas les changements.
ValidateOnSaveEnabled = false;
Ne détecte pas de changement de tracker
vous devez ajouter nuget
Install-Package Z.EntityFramework.Extensions
Vous pouvez maintenant utiliser le code suivant
var context = new MyContext();
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
context.BulkInsert(list);
context.BulkSaveChanges();
le secret est d'insérer dans une table d'étape vierge identique. Les Inserts éclairent vite. Ensuite, lancez un simple insérer à partir de cela dans votre grande table principale. Puis tronquez la table de staging prête pour la prochaine fournée.
ie.
insert into some_staging_table using Entity Framework.
-- Single insert into main table (this could be a tiny stored proc call)
insert into some_main_already_large_table (columns...)
select (columns...) from some_staging_table
truncate table some_staging_table
avez-vous déjà essayé d'insérer par l'intermédiaire d'un travailleur d'arrière-plan ou d'une tâche?
dans mon cas, im insérant 7760 registres, distribués dans 182 tableaux différents avec des relations clés étrangères ( par NavigationProperties).
sans la tâche, il a fallu 2 minutes et demie.
Dans le cadre d'une tâche ( Task.Factory.StartNew(...)
), il a fallu 15 secondes.
Im seulement à faire le SaveChanges()
après l'ajout de toutes les entités du contexte. (pour s'assurer que les données l'intégrité)
toutes les solutions écrites ici n'aident pas parce que quand vous faites SaveChanges(), insert statements sont envoyés à la base de données un par un, c'est comme ça que fonctionne Entity.
et si votre voyage à la base de données et retour est de 50 ms par exemple, alors le temps nécessaire pour insérer est le nombre d'enregistrements x 50 ms.
vous devez utiliser BulkInsert, voici le lien: https://efbulkinsert.codeplex.com /
j'ai eu l'heure d'insertion réduit de 5-6 minutes à 10-12 secondes en l'utilisant.
Vous pouvez utiliser en Vrac "paquet 151920920" de la bibliothèque. La version 1.0.0 est utilisée dans les projets ayant un cadre D'entité >=6.0.0 .
plus de description peut être trouvé ici- Bulkoperation code source
[NOUVELLE SOLUTION POUR POSTGRESQL] Hey, je sais que c'est un vieux post, mais j'ai récemment rencontré un problème similaire, mais nous utilisions Postgresql. Je voulais utilisation efficace bulkinsert, ce qui s'est avéré être assez difficile. Je n'ai pas trouvé de bibliothèque libre pour le faire sur ce DB. Je n'ai trouvé que cet assistant: https://bytefish.de/blog/postgresql_bulk_insert / qui est aussi sur Nuget. J'ai écrit un petit mapper, qui AUTO mapped propriétés de la façon Entity Framework:
public static PostgreSQLCopyHelper<T> CreateHelper<T>(string schemaName, string tableName)
{
var helper = new PostgreSQLCopyHelper<T>("dbo", "\"" + tableName + "\"");
var properties = typeof(T).GetProperties();
foreach(var prop in properties)
{
var type = prop.PropertyType;
if (Attribute.IsDefined(prop, typeof(KeyAttribute)) || Attribute.IsDefined(prop, typeof(ForeignKeyAttribute)))
continue;
switch (type)
{
case Type intType when intType == typeof(int) || intType == typeof(int?):
{
helper = helper.MapInteger("\"" + prop.Name + "\"", x => (int?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type stringType when stringType == typeof(string):
{
helper = helper.MapText("\"" + prop.Name + "\"", x => (string)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type dateType when dateType == typeof(DateTime) || dateType == typeof(DateTime?):
{
helper = helper.MapTimeStamp("\"" + prop.Name + "\"", x => (DateTime?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type decimalType when decimalType == typeof(decimal) || decimalType == typeof(decimal?):
{
helper = helper.MapMoney("\"" + prop.Name + "\"", x => (decimal?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type doubleType when doubleType == typeof(double) || doubleType == typeof(double?):
{
helper = helper.MapDouble("\"" + prop.Name + "\"", x => (double?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type floatType when floatType == typeof(float) || floatType == typeof(float?):
{
helper = helper.MapReal("\"" + prop.Name + "\"", x => (float?)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
case Type guidType when guidType == typeof(Guid):
{
helper = helper.MapUUID("\"" + prop.Name + "\"", x => (Guid)typeof(T).GetProperty(prop.Name).GetValue(x, null));
break;
}
}
}
return helper;
}
Je l'utilise de la manière suivante (j'avais entité nommée entreprise):
var undertakingHelper = BulkMapper.CreateHelper<Model.Undertaking>("dbo", nameof(Model.Undertaking));
undertakingHelper.SaveAll(transaction.UnderlyingTransaction.Connection as Npgsql.NpgsqlConnection, undertakingsToAdd));
j'ai montré un exemple avec transaction, mais il peut aussi être fait avec connexion normale récupérée à partir du contexte. undertakingsToAdd est une liste de dossiers d'entités normales, que je veux grouper en DB.
Cette solution, à laquelle j'ai eu après quelques heures de recherche et d'essai, est comme vous pouvez vous attendre beaucoup plus rapide et enfin facile à utiliser et gratuit! Je vous conseille vraiment d'utiliser cette solution, non seulement pour les raisons mentionnées ci-dessus, mais aussi parce que c'est la seule avec laquelle je n'ai eu aucun problème avec Postgresql lui-même, beaucoup d'autres solutions fonctionnent parfaitement par exemple avec SqlServer.
Mais, pour plus de (+4000) insère je recommande d'utiliser une procédure stockée. joint de temps s'est écoulé. Je l'ai inséré 11.788 lignes dans 20"
c'est le code
public void InsertDataBase(MyEntity entity)
{
repository.Database.ExecuteSqlCommand("sp_mystored " +
"@param1, @param2"
new SqlParameter("@param1", entity.property1),
new SqlParameter("@param2", entity.property2));
}
utiliser la procédure stockée qui prend des données d'entrée sous forme de xml pour insérer des données.
de votre code C# insérez des données en xml.
E. g dans c#, la syntaxe serait comme ceci:
object id_application = db.ExecuteScalar("procSaveApplication", xml)