I am using EF6
and due to the low speed of AddRange()
method I need to use BulkInsert
. So I added the NuGet package of BulkInsert for
With modifications to the code in this blog post, here's what worked for my Code First Fluent API setup after encountering the same "The given key was not present in the dictionary"
error on BulkInsert()
. The only dependency here is the ToDataTable()
extension method found in the DataExtensions
snippet of the aforementioned post.
The relevant part is the GetColumnMappings()
method which gets the POCO class property's preferred name (the one you specified in code) as the source column name (in the enumerable-turned-datatable) and pairs it with the metadata member's name (the DB column name) as the destination column name.
GetColumnMappings():
private IEnumerable GetColumnMappings()
{
var storageMetadata = ((EntityConnection)objectContext.Connection).GetMetadataWorkspace().GetItems(DataSpace.SSpace);
var entityPropMembers = storageMetadata
.Where(s => (s.BuiltInTypeKind == BuiltInTypeKind.EntityType))
.Select(s => (EntityType)s)
.Where(p => p.Name == typeof(T).Name)
.Select(p => (IEnumerable)(p.MetadataProperties["Members"].Value))
.First();
var sourceColumns = entityPropMembers.Select(m => (string)m.MetadataProperties["PreferredName"].Value);
var destinationColumns = entityPropMembers.Select(m => m.Name);
return Enumerable.Zip(sourceColumns, destinationColumns, (s, d) => new SqlBulkCopyColumnMapping(s, d));
}
Full Code:
// Modified from: https://ruijarimba.wordpress.com/2012/03/25/bulk-insert-dot-net-applications-part1 and
// https://ruijarimba.wordpress.com/2012/03/18/entity-framework-get-mapped-table-name-from-an-entity/
internal class BulkInserter
{
private readonly ObjectContext objectContext;
private readonly IDbConnection connection;
internal BulkInserter(DbContext contextAdapter)
{
objectContext = ((IObjectContextAdapter)contextAdapter).ObjectContext;
connection = contextAdapter.Database.Connection;
}
public void Insert(IEnumerable items) where T : class
{
EnsureOpenConnection();
using (var bulkCopy = new SqlBulkCopy((SqlConnection)connection)
{
DestinationTableName = GetTableName(),
})
{
foreach (var mapping in GetColumnMappings())
{
bulkCopy.ColumnMappings.Add(mapping);
}
bulkCopy.WriteToServer(items.ToDataTable());
}
}
private void EnsureOpenConnection()
{
if (connection.State == ConnectionState.Closed)
{
connection.Open();
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
private string GetTableName() where T : class
{
string sql = objectContext.CreateObjectSet().ToTraceString();
Regex regex = new Regex("FROM (?.*) AS");
Match match = regex.Match(sql);
string table = match.Groups["table"].Value;
return table;
}
private IEnumerable GetColumnMappings()
{
var storageMetadata = ((EntityConnection)objectContext.Connection).GetMetadataWorkspace().GetItems(DataSpace.SSpace);
var entityPropMembers = storageMetadata
.Where(s => (s.BuiltInTypeKind == BuiltInTypeKind.EntityType))
.Select(s => (EntityType)s)
.Where(p => p.Name == typeof(T).Name)
.Select(p => (IEnumerable)(p.MetadataProperties["Members"].Value))
.First();
var sourceColumns = entityPropMembers.Select(m => (string)m.MetadataProperties["PreferredName"].Value);
var destinationColumns = entityPropMembers.Select(m => m.Name);
return Enumerable.Zip(sourceColumns, destinationColumns, (s, d) => new SqlBulkCopyColumnMapping(s, d));
}
}
- 热议问题