Forma mais rápida de inserção na estrutura de entidades
estou a perguntar isto por causa do cenário em que se tem um TransactionScope activo e a inserção é enorme (4000+). Ele pode potencialmente durar mais de 10 minutos (Tempo Limite padrão das transações), e isso levará a uma transação incompleta.
25 answers
À sua observação nos comentários à sua pergunta:
É a pior coisa que podes fazer! Chamando"...Mudanças de sabor ( para cada registo )..."
SaveChanges()
para cada registo, o volume diminui imenso. Eu faria alguns testes simples que provavelmente melhorariam o desempenho:
- Liga para os registos de uma vez por todas.
- Ligue
SaveChanges()
depois, por exemplo, de 100 registos. - ligar
SaveChanges()
depois de, por exemplo, 100 registos e elimine o contexto e crie um novo. - desactivar a detecção de alterações
Para inserções a granel estou a trabalhar e a experimentar um padrão como este:
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;
}
Tenho um programa de testes que insere 560.000 entidades (9 Propriedades escalar, sem propriedades de navegação) no DB. Com este código, funciona em menos de 3 minutos.
Para o desempenho é importante chamar SaveChanges()
depois de" muitos " registros ("muitos" em torno de 100 ou 1000). Também melhora o desempenho para eliminar o contexto após as SaveChanges e criar um novo. Isto limpa o contexto de todas as entidades, SaveChanges
não faz isso, as entidades ainda estão ligadas ao contexto no estado Unchanged
. É o tamanho crescente de entidades ligadas no contexto que atrasa a inserção passo a passo. Portanto, é útil esclarecê-lo depois de algum tempo.
- commitCount = 1, recreateContext = false: muitas horas (Esse é o seu procedimento atual)
- commitCount = 100, recreateContext = false: mais de 20 minutos
- commitCount = 1000, recreateContext = false: 242 sec
- commitCount = 10000, recreateContext = false: 202 sec
- commitCount = 100000, recreateContext = false: 199 sec
- Número de commitCount = 1000000, recreateContext = false: fora da memória
- Número de commitCount = 1, recreateContext = true: mais de 10 minutos
- commitCount = 10, recreateContext = true: 241 sec
- commitCount = 100, recreateContext = true: 164 sec
- commitCount = 1000, recreateContext = true: 191 sec
O comportamento no primeiro ensaio acima é que o desempenho é muito não linear e diminui extremamente ao longo do tempo. ("Muitas horas" é uma estimativa, eu nunca terminei este teste, Parei em 50.000 entidades depois de 20 minutos.) Este comportamento não linear não é tão significativo em todos os outros ensaios.
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
A forma mais rápida seria usando Extensão de inserção a granel, que eu desenvolvi.
Ele usa o SqlBulkCopy e o leitor de dados personalizado para obter o desempenho máximo. Como resultado, é mais de 20 vezes mais rápido do que o uso regular de inserir ou AddRange
A utilização é extremamente simples
context.BulkInsert(hugeAmountOfEntities);
Você deve olhar para usar o {[[0]} para isto. Aqui está a documentação , e é claro que existem muitos tutoriais online.
Desculpa, eu sei que estavas à procura de uma resposta simples para fazer o EF fazer o que queres, mas as operações a granel não são para o que os ORMs servem.SqlBulkCopy
é a forma mais rápida de transferir os registos de massa de uma fonte de dados para outra. Usei isto para copiar os registos de 20K e demorou menos de 3 segundos. Dê uma olhada no exemplo abaixo.
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();
}
}
}
- 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
Então eu concentrei-me no que está a acontecer quando você reduz o tamanho do lote para um valor algures entre 10 e 100, e aqui estão os meus resultados (estou a usar diferentes conteúdos das linhas, por isso os meus tempos são de valor diferente):
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
Com base nos meus resultados, o óptimo real é cerca de 30 para o tamanho do lote. São menos de 10 e 100. O problema é que não faço ideia porque é que 30 é o ideal., nem poderia ter encontrado uma explicação lógica para isso.
Eu recomendaria este artigo sobre como fazer inserções em massa usando EF.
Estrutura da entidade e inserções lentas a granel
Ele explora estas áreas e compara a perfeição:
- default EF (57 minutos para completar a adição de 30.000 registos)
- substituição por: ADO.NET Código (25 segundos para os mesmos 30.000)
- aumento do contexto-manter o gráfico de contexto activo pequeno usando um novo contexto para cada unidade de trabalho (os mesmos 30 000 inserções tomam 33 segundos)
- listas grandes-desligue o AutoDetectChangesEnabled (reduz o tempo para cerca de 20 segundos)
- Resistência (até 16 segundos)
- DbTable.AddRange () - (o desempenho está no intervalo de 12)
Como outras pessoas disseram SqlBulkCopy é a maneira de fazê-lo se você quer realmente bom inserir desempenho.
É um pouco complicado de implementar, mas há bibliotecas que podem ajudá-lo com isso. Há alguns por aí, mas desta vez vou mostrar a minha própria biblioteca. https://github.com/MikaelEliasson/EntityFramework.Utilities#batch-insert-entitiesO único código que precisarias é:
using (var db = new YourDbContext())
{
EFBatchOperation.For(db, db.BlogPosts).InsertAll(list);
}
Então, é muito mais rápido? Muito difícil de dizer porque é depende de tantos fatores, desempenho do computador, rede, Tamanho do objeto etc. Os testes de desempenho que fiz sugerem que as Entidades de 25k podem ser inseridas em cerca de 10s da maneira padrão em localhost se você otimizar a sua configuração de EF como mencionado nas outras respostas. Com o EFUtilities que leva cerca de 300ms. ainda mais interessante é que eu salvei cerca de 3 milhões de entidades em menos de 15 segundos usando este método, com média de cerca de 200k entidades por segundo.
O tal o problema é claro se você precisar inserir dados relegados. Isto pode ser feito de forma eficaz no servidor sql usando o método acima, mas requer que você tenha uma estratégia de Geração de Id que lhe permita gerar id's no código app para o pai para que você possa definir as chaves estrangeiras. Isto pode ser feito usando GUIDs ou algo como hilo id geração.
Dispose()
contexto criar problemas se as entidades que você Add()
conta com outras entidades pré-carregadas (por exemplo, propriedades de navegação) no contexto
Uso um conceito semelhante para manter o meu contexto pequeno para conseguir o mesmo desempenho
Mas em vez deDispose()
o contexto e recriar, eu simplesmente destaco as entidades que 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;
} }
Enrola - o com tenta apanhar e TrasactionScope()
Se precisares,
não mostrá-los aqui para manter o código limpo
Tente usar um procedimento armazenado que irá obter um XML dos dados que deseja inserir.
Fiz uma extensão genérica do exemplo de @Slauma s acima;
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;
}
}
Utilização:
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();
}
}
Eu sei que esta é uma pergunta muito antiga, mas um cara aqui disse que desenvolveu um método de extensão para usar insert em massa com EF, e quando eu verifiquei, eu descobri que a biblioteca custa US $599 hoje (para um desenvolvedor). Talvez faça sentido para toda a biblioteca, no entanto, para apenas a inserção em massa isso é demais.
Aqui está um método de extensão muito simples que eu fiz. Eu uso isso em par com o banco de dados primeiro (não testar com o código primeiro, mas eu acho que funciona o mesmo). AlteraçãoYourEntities
com o nome do seu contexto:
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;
}
}
Podes usá-lo contra qualquer colecção que herde de IEnumerable
, assim:
await context.BulkInsertAllAsync(items);
Estou à procura da forma mais rápida de inserir no quadro da entidade.
Existem algumas bibliotecas de terceiros que suportam a introdução A Granel disponíveis:
- Z. EntityFramework.Extensões (Recomendadas)
- EFUtilities
- Quadro de direitos.BulkInsert
Ver: Entity Framework Bulk Insert library
Tenha cuidado, ao escolher uma biblioteca de insert bulk. Apenas as extensões da estrutura da entidade suportam todos os tipos de associações e heranças e é a única ainda suportada.
Declaração de exoneração de Responsabilidade : sou o proprietário da Entity Framework Extensions
Esta biblioteca permite-lhe efectuar todas as operações em massa de que necessita para os seus cenários:
- Grandes Savecanges
- Inserir A Granel
- Eliminação A Granel
- Actualização A Granel
- Junção A Granel
Exemplo
// 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;
});
De acordo com o meu conhecimento há {[[0]} em EntityFramework
para aumentar o desempenho das enormes inserções.
Neste cenário, você pode ir com SqlBulkCopy em ADO.net
para resolver o seu problema
Aqui está uma comparação de desempenho entre usar o Entity Framework e usar a classe SqlBulkCopy num exemplo realista: Como inserir objectos complexos na Base de dados do servidor SQL
Como outros já sublinharam, os ORMs não se destinam a ser utilizados em operações a granel. Oferecem flexibilidade, separação de preocupações e outros benefícios, mas as operações a granel (excepto a leitura a granel) não são um deles.
Outra opção é usar o SqlBulkTools disponível no Nuget. É muito fácil de usar e tem algumas características poderosas.
Exemplo:
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();
}
Veja a documentação para mais exemplos e utilização avançada. Disclaimer: eu sou o autor desta biblioteca e quaisquer opiniões são da minha própria opinião.
Uso 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;
}
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
AutoDetectChangesEnabled = false
Add, AddRange & SaveChanges: não detecta alterações.
ValidateOnSaveEnabled = false;
Não detecta o localizador de alterações
Deve adicionar nuget
Install-Package Z.EntityFramework.Extensions
Agora pode usar o seguinte código
var context = new MyContext();
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
context.BulkInsert(list);
context.BulkSaveChanges();
O segredo é inserir numa tabela idêntica em branco. As inserções estão a iluminar-se rapidamente. Em seguida, execute um Único inserir a partir daí na sua tabela principal grande. Em seguida, truncar a mesa de preparação pronto para o próximo lote.
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
Só estou a fazer o SaveChanges()
depois de adicionar todas as Entidades ao contexto. (para garantir a integridade dos dados)
Todas as soluções aqui escritas não ajudam porque quando você faz SaveChanges (), inserir declarações são enviadas para o banco de dados um a um, é assim que a entidade funciona.
E se a sua viagem de ida e volta à base de dados for de 50 ms, por exemplo, o tempo necessário para inserir é o número de registos x 50 ms.
Você tem que usar BulkInsert, aqui está a ligação: https://efbulkinsert.codeplex.com/
O tempo de inserção foi reduzido de 5-6 minutos para 10-12 segundos usando-o.Pode utilizar pacote a granel biblioteca. Bulk Insert 1.0.0 version is used in projects having Entity framework > = 6.0.0 .
Mais Descrição Pode ser encontrada aqui- Código-Fonte da Bulkoperation
[NOVA SOLUÇÃO PARA POSTGRESQL] Ei, eu sei que é um post bastante antigo, mas eu encontrei recentemente um problema semelhante, mas nós estávamos usando Postgresql. Eu queria usar bulkinsert eficaz, o que acabou por ser muito difícil. Não encontrei nenhuma biblioteca livre para o fazer neste cadáver. Só encontrei este ajudante.: https://bytefish.de/blog/postgresql_bulk_insert/ que também está em Nuget. Eu escrevi um pequeno mapeador, que auto mapeou propriedades da forma como entidade Enquadramento:
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;
}
USO - o da seguinte forma (tinha uma entidade com nome de Empresa):
var undertakingHelper = BulkMapper.CreateHelper<Model.Undertaking>("dbo", nameof(Model.Undertaking));
undertakingHelper.SaveAll(transaction.UnderlyingTransaction.Connection as Npgsql.NpgsqlConnection, undertakingsToAdd));
Mostrei um exemplo com a transacção, mas também pode ser feito com a ligação normal recuperada do contexto. undertakingsToAdd é enumerável de registos de entidades normais, que eu quero transformar em DB.
Esta solução, para a qual eu tenho após algumas horas de pesquisa e tentativa, é como você poderia esperar muito mais rápido e finalmente fácil de usar e livre! Aconselho-te a usar isto. solução, não só pelas razões mencionadas acima, mas também porque é o único com o qual eu não tinha problemas com o Postgresql em si, muitas outras soluções funcionam perfeitamente, por exemplo, com SqlServer.
Mas, para mais de (+4000) inserções eu recomendo usar o procedimento armazenado. anexou o tempo decorrido. Eu inseri 11.788 linhas em 20"
É o código. public void InsertDataBase(MyEntity entity)
{
repository.Database.ExecuteSqlCommand("sp_mystored " +
"@param1, @param2"
new SqlParameter("@param1", entity.property1),
new SqlParameter("@param2", entity.property2));
}
Utilizar o procedimento armazenado que recebe dados de entrada sob a forma de xml para inserir dados.
A partir do seu código C# Passe inserir os dados como xml.
E. G Em C#, a sintaxe seria assim:
object id_application = db.ExecuteScalar("procSaveApplication", xml)