Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF.BulkInsert and Glimpse - not playing together well

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??

like image 605
marc_s Avatar asked Mar 11 '23 18:03

marc_s


1 Answers

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.

like image 70
Gediminas Soliškis Avatar answered Mar 23 '23 18:03

Gediminas Soliškis