I have an EF6 / ASP.NET 4.5 Webforms solution up and running, and now I need to add some functionality to allow bulk inserts from Excel files.
I am aware that EF out of the box isn't optimized for bulk operations, so I looked around and found "EF BulkInsert" (https://efbulkinsert.codeplex.com/) to facilitate just this.
I tried it in a test app, and it worked wonderfully - but when I included it in my actual main app, it broke down. When trying to do the actual bulk insert call, the system crashes with an exception:
BulkInsertProviderNotFoundException: BulkInsertProvider not found for 'Glimpse.Ado.AlternateType.GlimpseDbConnection. To register new provider use EntityFramework.BulkInsert.ProviderFactory.Register() method'
Now I'm unsure if this is the fault of Glimpse or EF BulkInsert (or both), and unfortunately, I cannot seem to find any solution - neither of the makers of these pieces of software is providing any insights or workarounds....
Has anyone here stumbled across this same problem, and found a solution for it??
This problem occurs because Glimpse wraps DbConnection and EF BulkInsert extension tries to access it's private field "_connectionString" which is not there. I would blame EF BulkInsert in this case as accessing private members is just bad practice and no developer in Glimpse team could have anticipated that.
To solve this problem I have written a custom which inherits from EfSqlBulkInsertProviderWithMappedDataReader (default provider):
public class GlimpseProvider : EfSqlBulkInsertProviderWithMappedDataReader, IEfBulkInsertProvider
{
private static object GetPrivateFieldValue(object obj, string propName) {
if (obj == null) throw new ArgumentNullException("obj");
Type t = obj.GetType();
FieldInfo fieldInfo = null;
PropertyInfo propertyInfo = null;
while (fieldInfo == null && propertyInfo == null && t != null) {
fieldInfo = t.GetField(propName,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldInfo == null) {
propertyInfo = t.GetProperty(propName,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
}
t = t.BaseType;
}
if (fieldInfo == null && propertyInfo == null)
throw new ArgumentOutOfRangeException("propName",
string.Format("Field {0} was not found in Type {1}", propName, obj.GetType().FullName));
if (fieldInfo != null)
return fieldInfo.GetValue(obj);
return propertyInfo.GetValue(obj, null);
}
protected override IDbConnection DbConnection {
get { return (IDbConnection)GetPrivateFieldValue(this.Context.Database.Connection, "InnerConnection"); }
}
}
Now Register this provider somewhere. I did it in context OnModelCreating method.
EntityFramework.BulkInsert.ProviderFactory.Register<GlimpseProvider>("Glimpse.Ado.AlternateType.GlimpseDbConnection");
Be aware that I've tested this only with basic usage of EF BulkInsert.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With