我正在寻找插入实体框架的最快方法。
我之所以这样问,是因为您有一个活动的TransactionScope且插入量很大(超过4000个)。它可能会持续10分钟以上(默认的事务超时),这将导致不完整的事务。
我正在寻找插入实体框架的最快方法。
我之所以这样问,是因为您有一个活动的TransactionScope且插入量很大(超过4000个)。它可能会持续10分钟以上(默认的事务超时),这将导致不完整的事务。
Answers:
在对您的问题的评论中发表评论:
“ ... SavingChanges(针对每个记录)...”
那是你最糟糕的事情!调用SaveChanges()
每个记录都会大大降低批量插入的速度。我将做一些简单的测试,很可能会提高性能:
SaveChanges()
在所有记录后调用一次。SaveChanges()
例如100条记录。SaveChanges()
例如,调用100条记录并处理上下文并创建一个新的。对于批量插入,我正在尝试以下模式:
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;
}
我有一个测试程序,该程序将560.000实体(9个标量属性,没有导航属性)插入数据库。使用此代码,它可以在不到3分钟的时间内运行。
为了提高性能,重要的是要调用SaveChanges()
“许多”记录(“许多”大约为100或1000)。它还提高了在SaveChanges之后处理上下文并创建新上下文的性能。这会清除所有SaveChanges
实体的上下文,但不会这样做,实体仍然以state附加到上下文Unchanged
。在上下文中,附加实体的大小不断增长,这会逐步降低插入速度。因此,一段时间后清除它会很有帮助。
以下是我的560000个实体的一些度量值:
上面的第一个测试中的行为是性能是非常非线性的,并且随着时间的推移会大大降低。(“许多小时”是一个估计,我从未完成此测试,在20分钟后我停止在50.000个实体上。)这种非线性行为在所有其他测试中都不那么重要。
AutoDetectChangesEnabled = false;
在DbContext上进行设置。它也有一个很大的额外性能的影响:stackoverflow.com/questions/5943394/...
DbContext
,NOT ObjectContext
?
这种组合足以提高速度。
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
您应该看看System.Data.SqlClient.SqlBulkCopy
为此使用。这是文档,当然在线上有很多教程。
抱歉,我知道您正在寻找一个简单的答案,以使EF能够执行所需的操作,但是批量操作并不是ORM真正的目的。
我同意亚当·拉基斯(Adam Rackis)的观点。SqlBulkCopy
是将批量记录从一个数据源传输到另一个数据源的最快方法。我用它来复制2万条记录,花费了不到3秒的时间。看下面的例子。
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();
}
}
}
AsDataReader()
扩展方法,在此答案中说明:stackoverflow.com/a/36817205/1507899
我将推荐这篇有关如何使用EF进行批量插入的文章。
他探索了这些领域并比较了性能:
因为这里从来没有提到过,所以我想在这里推荐EFCore.BulkExtensions
context.BulkInsert(entitiesList); context.BulkInsertAsync(entitiesList);
context.BulkUpdate(entitiesList); context.BulkUpdateAsync(entitiesList);
context.BulkDelete(entitiesList); context.BulkDeleteAsync(entitiesList);
context.BulkInsertOrUpdate(entitiesList); context.BulkInsertOrUpdateAsync(entitiesList); // Upsert
context.BulkInsertOrUpdateOrDelete(entitiesList); context.BulkInsertOrUpdateOrDeleteAsync(entitiesList); // Sync
context.BulkRead(entitiesList); context.BulkReadAsync(entitiesList);
我已经研究了Slauma的答案(这太了不起了,谢谢这个主意的人),并且我减小了批量大小,直到达到最佳速度为止。查看Slauma的结果:
可以看出,从1移到10,从10移到100时,速度会增加,但是从100移到1000时,插入速度又会下降。
因此,我专注于将批量大小减小到介于10到100之间的值时发生的情况,这是我的结果(我使用的行内容不同,所以我的时间值也不同):
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
根据我的结果,批量的实际最佳值约为30。它小于10和100。问题是,我不知道为什么30是最佳值,也找不到任何合理的解释。
就像其他人说的那样,如果要真正好的插入性能,则可以使用SqlBulkCopy。
实现起来有点麻烦,但是有一些库可以帮助您。那里有一些,但是这次我将无耻地插入我自己的库:https : //github.com/MikaelEliasson/EntityFramework.Utilities#batch-insert-entities
您唯一需要的代码是:
using (var db = new YourDbContext())
{
EFBatchOperation.For(db, db.BlogPosts).InsertAll(list);
}
那么它快多少呢?很难说,因为它取决于许多因素,计算机性能,网络,对象大小等。我进行的性能测试表明,可以在10s左右的标准时间内插入25k实体,如果您像优化EF配置那样,在本地主机上在其他答案中提到。使用EFUtilities大约需要300毫秒。更有趣的是,使用这种方法,我在15秒内节省了大约300万个实体,平均每秒可存储约20万个实体。
当然,一个问题是是否需要插入相关数据。可以使用上述方法有效地将其导入sql server,但它要求您具有ID生成策略,该策略可以让您在父代的应用代码中生成ID,以便您可以设置外键。可以使用GUID或类似HiLo id生成的方法来完成。
EFBatchOperation
有一个传递DbContext
给您的构造函数,而不是传递给每个静态方法。InsertAll
和UpdateAll
可以自动找到集合的通用版本(类似于DbContext.Set<T>
)也不错。
Dispose()
如果您Add()
依赖上下文中其他预加载的实体(例如,导航属性),则上下文会产生问题
我使用类似的概念来使上下文保持较小以实现相同的性能
但是,Dispose()
除了上下文和重新创建,我只是分离已经存在的实体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;
} }
用try catch包裹它,TrasactionScope()
如果需要的话,在这里不显示它们以保持代码干净
我知道这是一个非常老的问题,但是这里的一个人说,开发了一种扩展方法来将批量插入与EF结合使用,当我检查时,我发现该库今天的售价为599美元(对于一名开发人员而言)。也许对整个库来说都有意义,但是对于批量插入来说,这太过分了。
这是我做的一个非常简单的扩展方法。我先将其与数据库配对使用(不先进行代码测试,但我认为工作原理相同)。更改YourEntities
您的上下文名称:
public partial class YourEntities : DbContext
{
public async Task BulkInsertAllAsync<T>(IEnumerable<T> entities)
{
using (var conn = new SqlConnection(Database.Connection.ConnectionString))
{
await conn.OpenAsync();
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;
}
}
您可以将其用于继承自的任何集合IEnumerable
,例如:
await context.BulkInsertAllAsync(items);
await bulkCopy.WriteToServerAsync(table);
尝试使用存储过程,该存储过程将获取要插入的数据的XML。
我在上面的示例中对@Slauma的示例进行了通用扩展;
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;
}
}
用法:
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();
}
}
我正在寻找插入实体框架的最快方法
有一些支持批量插入的第三方库:
请参阅:实体框架批量插入库
选择批量插入库时请小心。只有Entity Framework Extensions支持所有类型的关联和继承,并且它仍然是唯一受支持的一种。
免责声明:我是Entity Framework Extensions的所有者
该库使您可以执行方案所需的所有批量操作:
例
// 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;
});
用途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 =假
添加,添加范围和保存更改:不检测更改。
ValidateOnSaveEnabled = false;
不检测变化跟踪器
您必须添加nuget
Install-Package Z.EntityFramework.Extensions
现在您可以使用以下代码
var context = new MyContext();
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
context.BulkInsert(list);
context.BulkSaveChanges();
SqlBulkCopy超级快
这是我的实现:
// at some point in my calling code, I will call:
var myDataTable = CreateMyDataTable();
myDataTable.Rows.Add(Guid.NewGuid,tableHeaderId,theName,theValue); // e.g. - need this call for each row to insert
var efConnectionString = ConfigurationManager.ConnectionStrings["MyWebConfigEfConnection"].ConnectionString;
var efConnectionStringBuilder = new EntityConnectionStringBuilder(efConnectionString);
var connectionString = efConnectionStringBuilder.ProviderConnectionString;
BulkInsert(connectionString, myDataTable);
private DataTable CreateMyDataTable()
{
var myDataTable = new DataTable { TableName = "MyTable"};
// this table has an identity column - don't need to specify that
myDataTable.Columns.Add("MyTableRecordGuid", typeof(Guid));
myDataTable.Columns.Add("MyTableHeaderId", typeof(int));
myDataTable.Columns.Add("ColumnName", typeof(string));
myDataTable.Columns.Add("ColumnValue", typeof(string));
return myDataTable;
}
private void BulkInsert(string connectionString, DataTable dataTable)
{
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
SqlTransaction transaction = null;
try
{
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();
}
catch (Exception)
{
transaction?.Rollback();
throw;
}
}
}
[2019更新] EF Core 3.1
按照上述说明,在EF Core中禁用AutoDetectChangesEnabled可以完美地工作:插入时间除以100(从几分钟到几秒钟,具有交叉表关系的10k条记录)
更新的代码是:
context.ChangeTracker.AutoDetectChangesEnabled = false;
foreach (IRecord record in records) {
//Add records to your database
}
context.ChangeTracker.DetectChanges();
context.SaveChanges();
context.ChangeTracker.AutoDetectChangesEnabled = true; //do not forget to re-enable
这是在一个实际示例中使用实体框架和使用SqlBulkCopy类之间的性能比较:如何将复杂对象批量插入SQL Server数据库
正如其他人已经强调的那样,ORM不能用于批量操作。它们提供了灵活性,关注点分离和其他好处,但是批量操作(批量读取除外)不是其中之一。
另一种选择是使用Nuget提供的SqlBulkTools。它非常易于使用,并具有一些强大的功能。
例:
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();
}
有关更多示例和高级用法,请参阅文档。免责声明:我是该库的作者,任何观点都是我个人的观点。
据我所知no BulkInsert
,EntityFramework
可以提高巨大刀片的性能。
在这种情况下,您可以去使用SqlBulkCopy在ADO.net
为您解决问题
WriteToServer
需要重载的重载DataTable
。
您是否曾经尝试通过后台工作人员或任务插入?
在我的情况下,我将插入7760个寄存器,这些寄存器分布在具有外键关系的182个不同表中(按NavigationProperties)。
没有任务,花了2分半钟。在任务(Task.Factory.StartNew(...)
)中,耗时15秒。
我只是SaveChanges()
在将所有实体添加到上下文中之后执行此操作。(以确保数据完整性)
[Postgresql的新解决方案]嗨,我知道这是一篇很老的文章,但是我最近遇到了类似的问题,但是我们使用的是Postgresql。我想使用有效的bulkinsert,事实证明这很困难。我尚未在该数据库上找到任何合适的免费库来这样做。我只找到了这个帮助程序:https : //bytefish.de/blog/postgresql_bulk_insert/也在Nuget上。我写了一个小的映射器,它以实体框架的方式自动映射属性:
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;
}
我以以下方式使用它(我有一个实体叫做Undertaking):
var undertakingHelper = BulkMapper.CreateHelper<Model.Undertaking>("dbo", nameof(Model.Undertaking));
undertakingHelper.SaveAll(transaction.UnderlyingTransaction.Connection as Npgsql.NpgsqlConnection, undertakingsToAdd));
我展示了一个有关事务的示例,但是也可以通过从上下文中检索到的普通连接来完成。undertakingsToAdd是普通实体记录的枚举,我想将其批量插入数据库。
经过数小时的研究和尝试后,我获得了这个解决方案,正如您所期望的那样,它更快,最终易于使用且免费!我真的建议您使用此解决方案,这不仅是因为上述原因,而且还因为它是我对Postgresql本身没有问题的唯一解决方案,许多其他解决方案都可以完美使用,例如与SqlServer一起使用。
秘诀是将其插入相同的空白登台表中。嵌件快速减轻重量。然后运行一个单一的从插入到你的主大表。然后截断暂存表以准备下一批。
即。
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
使用此技术可以提高在Entity Framework中插入记录的速度。在这里,我使用一个简单的存储过程来插入记录。为了执行此存储过程,我使用了执行原始SQL 的Entity Framework的.FromSql()方法。
CREATE PROCEDURE TestProc
@FirstParam VARCHAR(50),
@SecondParam VARCHAR(50)
AS
Insert into SomeTable(Name, Address) values(@FirstParam, @SecondParam)
GO
接下来,遍历所有4000条记录并添加执行存储的Entity Framework代码
程序每100次循环一次。
为此,我创建了一个字符串查询来执行此过程,并继续将每组记录追加到该字符串查询。
然后检查循环是否以100的倍数运行,在这种情况下,请使用执行循环.FromSql()
。
因此,对于4000条记录,我只需要执行该过程仅 4000/100 = 40次。
string execQuery = "";
var context = new MyContext();
for (int i = 0; i < 4000; i++)
{
execQuery += "EXEC TestProc @FirstParam = 'First'" + i + "'', @SecondParam = 'Second'" + i + "''";
if (i % 100 == 0)
{
context.Student.FromSql(execQuery);
execQuery = "";
}
}