动态数据表到实体*无需*提前进行硬编码...?

2024-01-13

问题:

问:为什么不能/如何动态使用 DataTable 中的数据在使用反射(?)的函数中创建 LINQ/EF 以根据可用内容创建实体实例?

我看到了很多很多的问题和关于硬编码,但没有人这样做动态地。我正在寻找一种替代方法,不必为我的所有实体维护硬编码代码......

我的方法的背景/验证:

  1. 我所处的情况是我有很多很多实体。
  2. 我正在使用 EF6 Code-First、MVC5 和 ASP.NET,管理员会上传电子表格。每个工作簿都转换为一个数据集,每个选项卡(工作表)都转换为一个数据表。
  3. 这一切我都做得很好,以DataTable名称作为实体类的名称。
  4. 为用户提供了一个模板电子表格,其中已经包含了他们需要填写的列名称作为顶行。在这个问题之后我将解决必须手动解决的问题。 [用户应该能够选择一个类,并且应该制作一个工作簿供他们使用适当的列标题动态下载,但这在列表中]
  5. 我的问题从一个填写的工作表开始,该工作表已被带入每个类的数据表中,由其选项卡名称/数据表名称决定。

Given:-我知道类的名称(来自 dt.Name),并且我已经验证它是一个有效的实体。 -我知道我将使用每个 DataRow 更新的列的名称,因为它们位于 dt 的列名称中。

问题重述,现在有上下文: 为什么不能/如何动态使用 DataTable 中的数据在使用反射(?)的函数中创建 LINQ/EF 以根据可用内容创建实体实例?

[Pseudo-Code]
public void DataTableToEntities(DataTable dt){
    string entityClassName = dt.Name;
    ArrayList/List<string> colNames = dt.Columns. names, ...
    ....
    using (MyContext ctx = new MyContext()){
        while (row dtRow in dtRows){
            // magic follows:
            DeterminedEntity de = new DeterminedEntity();
            // populate de with dtRow
            ctx.[DeterminedEntity].Add(de);
            // magic ends...
        }
        ctx.SaveChanges;
    }
}

理由:

我可以随意添加、编辑和删除实体,而不必像上面那样在导入场景中对这些细微的更改进行硬编码。

下一步:处理动态工作簿和工作表创建作为上述流程的上传模板,其中工作簿 -> 数据集, and 工作表 -> 数据表.

进步:2016年11月6日

这个问题的关键似乎是如何仅从名称实例化 DBContext 类实体的实例。

我的 Scratch 控制台应用程序是一个单独的项目(相同的解决方案),所有模型和内容都复制...

到目前为止我已经得到:

static void Main(string[] args)
{
    ScratchProgram s = new ScratchConsole1.ScratchProgram();
    Console.WriteLine("starting");
    string fileLocation = @"C:\Users\...\SomeDbSetClass_test.xlsx";
    string tableName = "SomeDbSetClass";
    //----------------------------------------------------------
    // FreeSpire.xls
    Workbook wb = new Workbook();
    wb.LoadFromFile(fileLocation);
    Console.WriteLine("wb.WorkSheets count: " + wb.Worksheets.Count);
    //----------------------------------------------------------
    Worksheet ws = wb.Worksheets[tableName];
    Console.WriteLine("ws.Rows count: " + ws.Rows.Count());
    //----------------------------------------------------------
    DataTable dt = new DataTable(tableName);
    dt = ws.ExportDataTable();
    Console.WriteLine("dt.Rows.Count: " + dt.Rows.Count);
    Console.WriteLine("dt.Name: " + dt.TableName);
    //==========================================================
    string pathToAssembly = @"C:\...\ScratchConsole1.dll";
    var aClass = s.CreateInstanceOf(dt.TableName, pathToAssembly);
    // Now I have a valid class of the program-NOT the ef ctx...
    Console.WriteLine("aClass.FullName: " + aClass.GetType().FullName);

    MethodInfo[] aMethods = aClass.GetType().GetMethods();
    // now I have an array of all get/sets... "get_<method>" and "set_<method>"
    // let's iterate through all the methods, printing them:
    for (int i2 = 0;i2 < aMethods.Count() ; i2++)
    {
        MethodInfo mi = aMethods[i2];
        Console.WriteLine("method: " + mi.Name);
    }
    // the above isn't really useful, as I already have the property names in the dt header row
    using (DatabaseContext ctx = new DatabaseContext())
    {
        //==========================================================
        // i is used as column index below, as dr.ItemArray is an array...
        int i = 0; 
        // each dr should create a new instance of the ctx's ef class...
        foreach (DataRow dr in dt.Rows)
        {
            ???
            ...Create new instance in ctx, using as class name: dt.TableName...
            ctxClass <--- assuming made using aClass
            ???

            // now we can load each class property with the value from the dr:
            foreach (string drItem in dr.ItemArray)
            {
                Console.WriteLine(String.Format("================= col ================="));
                string entAttrName = dt.Columns[i].ToString(); // this is fine as string, but...
                string entAttrValue = dr[i].ToString(); // this is NOT <--- see Note1 below

                Console.WriteLine("[" + i + "] Item: " + entAttrName.ToString());
                Console.WriteLine("[" + i + "] Value: " + entAttrValue.ToString());

                ???
                ctxClass.[entAttrName.ToString()] = entAttrValue.ToString(); <--- see Note1 below
                ???

                //==============================================================================
                // Note1:
                // the above is far less than ideal, as it has every column/attribute/property type // being used as a String... Obviously, we want to leave doubles as doubles, ints as // ints, etc.
                
                // This becomes a MUCH larger problem when we introduce entities as properties... 
                // like a State entity with many City entities as a List<State> as a property...
                //==============================================================================
                i++;
            }
            ctx.[ef class].Add(ctxClass);
        }
        ctx.SaveChanges();
    }
    Console.WriteLine("end.");
    Console.ReadKey();
}

public object CreateInstanceOf(string ClassName, string AssemblyFullPath)
{
    var assemblyFullPath = Assembly.LoadFrom(@"C:\...\ScratchConsole1.exe");
    var assembly = Assembly.GetExecutingAssembly();
    var type = assembly.GetTypes().First(t => t.Name == ClassName);
    return Activator.CreateInstance(type);
}

我希望这能让事情更容易理解。:)

更新和解决方案!一个SO用户,格特·阿诺德 https://stackoverflow.com/users/861716/gert-arnold,通过更改一行解决了问题这个帖子 https://stackoverflow.com/questions/40496667/how-can-i-dynamically-add-inherited-properties-to-ef-datastore?noredirect=1#comment68237920_40496667:

// All details from the property to update/set:
//PropertyInfo theProp = thisTypeInfo.GetDeclaredProperty(entAttrName);
PropertyInfo theProp = thisTypeInfo.GetProperty(entAttrName);

格特的解释:

thisTypeInfo.GetDeclaredProperty 获取类型声明的属性 它本身,而不是它的超类型。使用 thisTypeInfo.GetProperty。 ——格特·阿诺德

我不敢相信我能够以更聪明的人可以解决的方式构建一个我几乎不理解的问题!

=================================================== =========================


解决办法就一句话:

该程序采用电子表格文件 (.xlsx),读取 EF DbSet 类的选项卡名称以及属性名称和值的列名称和值,并将它们作为单独的实体保存在 EF 安装的数据存储中(适用于SQLite 和 SQL Server 2014).

最酷的部分是,应用程序中无需对 EF 类名称、属性等进行硬编码。这意味着您可以创建 Exceltemplate,让某人填写(只需填写您在模板中提供的列),然后就可以轻松导入该文件。

您需要为自己重新创建的所有内容都在这篇文章中。

我希望将其用于我正在编写的自己的应用程序,并且有点惊讶的是没有人想做同样的事情。对于数百个 EF 类和基类,答案(即使在这里)是蹲下来,咬紧牙关,对所有内容进行硬编码。

我要发帖工作代码尽我所能。对于任何试图让自己的软件更易于使用的人来说,这段代码希望是向前迈出的一大步。为了完全地隔离问题/Poc/答案,我使用:

VS 2015、最新的 SQLite、SQLite.CodeFirst、System.Data.SQLite[.Linq 和 .EF6](

Notes:
- 我在正常系统中使用SQL 2014 Ent,但发现SQLite具有相同的性能。事实上,这个示例和下面的计时是在 SQLite 数据库文件上的!
- 下面的计时是在我的开发笔记本电脑上进行的,该笔记本电脑在装有 VS2015 的 VirtBox VM 中运行 Win10。同一台笔记本电脑上的另一个 VM 正在运行 SQL 2014 Enterprise,但对于此测试示例,我在同一个 Win10 VM 上使用 SQLite。
-My MyDbContext.cs and 配置.cs文件是简单的,没有播种等。

public DbSet<Person> Persons { get; set; }
public DbSet<Child> Children { get; set; }

- 有一个简单的 test.xlsx 文件,其中包含要插入数据库的值。

这是它的 .csv:

sChildFoo,iChildBar,dChildBaz,PersonAge,PersonWeight,PersonName
Norwich,29884,1.2,34,123,Fred Flintstone
Waterford,34990,3.4,56,210,Barney Rubble

重要提示:工作表中的选项卡带有标签Child- 与您想要加载值的类完全相同。有 2 个数据/实体类,Person() 和 Child() 称为PersonChild.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DynamicEFLoading
{
    public abstract class Person
    {
        [Key]
        public int PersonId { get; set; }
        public int PersonAge { get; set; }
        public int PersonWeight { get; set; }
        public string PersonName { get; set; }
    }
    class Child : Person
    {
        [Key]
        [Column(Order = 0)]
        public int Id { get; set; }
        public string sChildFoo { get; set; }
        public int iChildBar { get; set; }
        public double dChildBaz { get; set; }
    }
}

正如您所看到的,所有 Child() 实例都继承了 Person() 的属性。我什至将 Person() 抽象化。

这是实质内容,正如我在评论中敢于装饰的那样,测试程序.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SQLite;
using NLog;
using System.Reflection;
using System.Data.Entity;
using Spire.Xls;
using System.Data;
using System.Collections;

namespace DynamicEFLoading
{
    class TestProgram
    {
        private static Logger logit = LogManager.GetCurrentClassLogger();
        static void Main()
        {
            DateTime dtStart = new DateTime(DateTime.Now.Ticks);
            DateTime dtStop = new DateTime();
            TestProgram s = new TestProgram();
            Utils u = new Utils();
            s.p("Starting at " + DateTime.Now.ToLongTimeString());
            // for this test, I leave this door open the whole time...
            using (MyDbContext ctx = new MyDbContext())
            {
                //###########################################################################
                //
                // create a row in db each time run...
                //
                Random rnd = new Random();
                // 
                Child c1 = new DynamicEFLoading.Child();
                // Age, Weight, Name all come from base class Person()
                c1.PersonAge = rnd.Next(120);
                c1.PersonWeight = rnd.Next(85, 300);
                c1.PersonName = String.Format("{0} {1}", Utils.GenerateName(6), Utils.GenerateName(8));
                s.p(String.Format("Created .Name: {0}", c1.PersonName));
                //
                c1.dChildBaz = rnd.NextDouble();
                c1.iChildBar = rnd.Next(99999);
                c1.sChildFoo = String.Format("{0}", Utils.GenerateName(10));
                s.p(String.Format("Created .sParentFoo: {0}", c1.sChildFoo));
                //
                ctx.Children.Add(c1);
                //_______________________________________________________
                ctx.SaveChanges();
                //###########################################################################
                //
                // in production, there would be no hard coding...
                //
                string fileLocation = @"C:\Users\<some user>\Desktop\test.xlsx";
                //
                // NOTE! Here I am specifying the only tab(ws name) in the wb. This is easily changed 
                //      to access all tabs by index, using Worksheet ws = wb.Worksheets[index], and
                //      a simple loop through them all. In my first test, I even verify the tab had
                //      a corresponding table in DB before continuing... 
                string tableName = "Child";
                //----------------------------------------------------------
                // freeSpire.xls
                Workbook wb = new Workbook();
                wb.LoadFromFile(fileLocation);
                //----------------------------------------------------------
                // see NOTE! just above...
                Worksheet ws = wb.Worksheets[tableName];
                //----------------------------------------------------------
                // create a DataTable
                DataTable dt = new DataTable(tableName);
                // load it with data from whoile worksheet (ws)
                dt = ws.ExportDataTable();
                // from now on, we use DataTable-not spreadsheet
                //----------------------------------------------------------
                s.p(String.Format("wb.WorkSheets count: " + wb.Worksheets.Count));
                s.p(String.Format("ws.Rows count: " + ws.Rows.Count()));
                s.p(String.Format("dt.Rows.Count: " + dt.Rows.Count));
                s.p(String.Format("dt.Name: " + dt.TableName));
                //==========================================================
                // getting assembly name programmatically fails when a project is inside a solution
                //  in VS. It assumes ...\ProjName\ProjName\... whis isn't how solutions go... 
                string pathToAssembly = @"C:\Users\<some user>\Documents\Visual Studio 2015\Projects\DynamicEFLoading\DynamicEFLoading\bin\Debug\DynamicEfLoading.exe";
                // string pathToAssembly = @".\DynamicEfLoading.exe";
                // create an 'anonymous', or ghost class:
                var aClass = u.CreateInstanceOf(dt.TableName, pathToAssembly);
                // display class type
                s.p(String.Format("aClass.FullName: " + aClass.GetType().FullName));
                //==========================================================
                //
                // creating a DbSet for the dt's entities. It isn't good enough to just create
                //  the class itself-it needs to be from the DbContext (ctx). or else you can't
                //  ctx.SaveChanges();    
                //
                s.p(String.Format("Creating 'dbs' object..."));
                DbSet dbs = ctx.Set(aClass.GetType());
                // But you can't att attributes/properties to a DbSet-only to the class it is
                //  derived from, so we then use the DbSet (dbs) for this class to create an
                //  empty class that we can populate & later add to DB via ctx:
                var theObj = dbs.Create(aClass.GetType());
                // make sure it's the right one:
                s.p(String.Format("GetType: " + theObj.GetType()));
                //____________________________________________________________________________
                int i = 0; // used to keep track of each column as we go through the dt
                foreach (DataRow dr in dt.Rows) // each dr in the dt is a separate instance of the theObj class
                {
                    s.p(String.Format("================= row =================================="));
                    i = 0; // I don't like to put var instantiation in a loop...
                    // each drItem is the content for the row (theObj)
                    foreach (string drItem in dr.ItemArray)
                    {
                        s.p(String.Format("================= col {0} ", i));
                        string entAttrName = dt.Columns[i].ToString();
                        string entAttrValue = dr[i].ToString();
                        // column (property) name:
                        s.p("[" + i + "] Item: " + entAttrName.ToString());
                        // the value of that property to load into this class' property
                        s.p("[" + i + "] Value: " + entAttrValue.ToString());
                        // which type of data is this property? (string, int32, double...)
                        // -also has data like if nullable, etc. of use in later refinements...
                        TypeInfo thisTypeInfo = theObj.GetType().GetTypeInfo();
                        // All details from the property to update/set:
                        PropertyInfo theProp = thisTypeInfo.GetProperty(entAttrName);
                        //___________________________________________________________________
                        // need to determine the property type, converting entAttrValuefrom string:
                        // good debugging info at this stage to see what we've discovered from the class dynamically at rn time...
                        s.p("theProp.DeclaringType.FullName of attr: " + theProp.DeclaringType.FullName);
                        s.p("theProp.GetSetMethod(true).ToString() of attr: " + theProp.GetSetMethod(true).ToString());
                        s.p("theProp.GetType().ToString() of attr: " + theProp.GetType().ToString());
                        s.p("theProp.Name of attr: " + theProp.Name);
                        s.p("theProp.PropertyType.ToString() of attr: " + theProp.PropertyType.ToString());
                        s.p("theProp.ReflectedType.ToString() of attr: " + theProp.ReflectedType.ToString());
                        s.p("theProp.ReflectedType.ToString() of attr: " + theProp.SetMethod.ReturnType.ToString());
                       /* update entAttrName with entAttrValue:
                        *
                        * At this point, my values in the DataTable are all strings, but the class itself 
                        *   stores that value as who-knows-what. So here I just parse out what kind it is from three
                        *   common types. In future, may need to add more, but for now, these are the big 4: 
                        * 
                        * String, Integer, DatTime, and Double
                        */
                        if (theProp.PropertyType.ToString() == "System.String")
                        {
                            theProp.SetValue(theObj, (String)entAttrValue);
                            logit.Debug("Set {0} value: {1}",
                                theProp.PropertyType.ToString(),
                                entAttrValue);
                        }
                        else if (theProp.PropertyType.ToString().Contains("System.Int32"))
                        {
                            theProp.SetValue(theObj, int.Parse(entAttrValue));
                            logit.Debug("Set {0} value: {1}",
                                theProp.PropertyType.ToString(),
                                entAttrValue);
                        }
                        else if (theProp.PropertyType.ToString().Contains("System.DateTime"))
                        {
                            IFormatProvider culture = new System.Globalization.CultureInfo("en-US", true);
                            DateTime dTime = DateTime.Parse(entAttrValue, culture, System.Globalization.DateTimeStyles.AssumeLocal);
                            theProp.SetValue(theObj, entAttrValue);
                            logit.Debug("Set {0} value: {1}",
                                theProp.PropertyType.ToString(),
                                entAttrValue);
                        }
                        else if (theProp.PropertyType.ToString().Contains("System.Double"))
                        {
                            theProp.SetValue(theObj, double.Parse(entAttrValue));
                            logit.Debug("Set {0} value: {1}",
                                theProp.PropertyType.ToString(),
                                entAttrValue);
                        }
                        else
                        {
                            logit.Error("Unexpected property type: {0} given. string value: {1}",
                                theProp.PropertyType.ToString(),
                                entAttrValue
                            );
                        }
                        i++; // increment column index...
                    } // end foreach (string drItem in dr.ItemArray...
                    // add class to context...
                    dbs.Add(theObj);
                    // to save one by one (each row):
                    ctx.SaveChanges();
                } // end of foreach (DataRow dr in dt.Rows...
                  // or... to save as batch (at end of worksheet):
                  // ctx.SaveChanges();
                  //###########################################################################
                dtStop = new DateTime(DateTime.Now.Ticks);
                TimeSpan tsDuration = dtStop - dtStart;
                s.p(String.Format("end... took {0} seconds.", tsDuration.TotalSeconds.ToString()));
                Console.ReadKey();
            } // end using DbContext...
        }
        /*
         * Convenience; writes to both...
         * 
         */
        //private static void p(string message)
        private void p(string message)
        {
            logit.Info(message);
            Console.WriteLine(message);
        }
    }
}

最后,这是Utils.cs包含 Utils() 类的文件。您会看到上面提到的这些被称为“u.*”,在 TestProgram.cs 顶部的实例化方式:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using NLog;
using System.Collections;
using System.Data;

namespace DynamicEFLoading
{
    class Utils
    {
        private static Logger logit = LogManager.GetCurrentClassLogger();

        public ArrayList HeadersFromDataTable(DataTable theDataTable)
        {
            ArrayList arHeaders = new ArrayList();
            try
            {
                arHeaders.AddRange(theDataTable.Columns);
                logit.Info("loaded {0} column headers...", arHeaders.Count);
            }
            catch (Exception ex)
            {
                logit.Fatal("exception: " + ex.ToString());
            }
            return arHeaders;
        }

        public object CreateInstanceOf(string ClassName, string AssemblyFullPath)
        {
            var assemblyFullPath = Assembly.LoadFrom(@"C:\Users\<some user>\Documents\Visual Studio 2015\Projects\PoliticWebSite\ScratchConsole1\bin\Debug\ScratchConsole1.exe");
            var assembly = Assembly.GetExecutingAssembly();
            //var assembly = Assembly.LoadFrom(assemblyFullPath);
            var type = assembly.GetTypes().First(t => t.Name == ClassName);
            return Activator.CreateInstance(type);
        }

        public static string GenerateName(int len)
        {
            Random rndSeed = new Random(DateTime.Now.Millisecond);
            Random r = new Random(rndSeed.Next());
            string[] consonants = { "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "l", "n", "p", "q", "r", "s", "sh", "zh", "t", "v", "w", "x" };
            string[] vowels = { "a", "e", "i", "o", "u", "ae", "y" };
            string Name = "";
            Name += consonants[r.Next(consonants.Length)].ToUpper();
            Name += vowels[r.Next(vowels.Length)];
            int b = 2; //b tells how many times a new letter has been added. It's 2 right now because the first two letters are already in the name.
            while (b < len)
            {
                //_________________________________________________________________
                rndSeed = new Random(DateTime.Now.Millisecond);
                r = new Random(rndSeed.Next());
                Name += consonants[r.Next(consonants.Length)];
                b++;
                //_________________________________________________________________
                rndSeed = new Random(DateTime.Now.Millisecond);
                r = new Random(rndSeed.Next());
                Name += vowels[r.Next(vowels.Length)];
                b++;
                //_________________________________________________________________
            }
            return Name;
        }
    }
}

那么,当程序遍历每一列(可以按任何顺序,顺便说一句)时,这一切看起来是什么样的?

2016-11-08 22:18:14.2500 INFO Starting at 10:18:14 PM
2016-11-08 22:18:14.3499 INFO Created .Name: Tytaetae Tytaetaetae
2016-11-08 22:18:14.3499 INFO Created .sParentFoo: Baebabababa
2016-11-08 22:18:15.2181 INFO wb.WorkSheets count: 2
2016-11-08 22:18:15.2181 INFO ws.Rows count: 3
2016-11-08 22:18:15.2338 INFO dt.Rows.Count: 2
2016-11-08 22:18:15.2338 INFO dt.Name: Child
2016-11-08 22:18:15.2487 INFO aClass.FullName: DynamicEFLoading.Child
2016-11-08 22:18:15.2487 INFO Creating 'dbs' object...
2016-11-08 22:18:15.2644 INFO GetType: DynamicEFLoading.Child
2016-11-08 22:18:15.2644 INFO ================= row ==================================
2016-11-08 22:18:15.2644 INFO ================= col 0 
2016-11-08 22:18:15.2801 INFO [0] Item: sChildFoo
2016-11-08 22:18:15.2801 INFO [0] Value: Norwich
2016-11-08 22:18:15.2801 INFO theProp.DeclaringType.FullName of attr: DynamicEFLoading.Child
2016-11-08 22:18:15.2958 INFO theProp.GetSetMethod(true).ToString() of attr: Void set_sChildFoo(System.String)
2016-11-08 22:18:15.2958 INFO theProp.GetType().ToString() of attr: System.Reflection.RuntimePropertyInfo
2016-11-08 22:18:15.3114 INFO theProp.Name of attr: sChildFoo
2016-11-08 22:18:15.3114 INFO theProp.PropertyType.ToString() of attr: System.String
2016-11-08 22:18:15.3271 INFO theProp.ReflectedType.ToString() of attr: DynamicEFLoading.Child
2016-11-08 22:18:15.3271 INFO theProp.ReflectedType.ToString() of attr: System.Void
2016-11-08 22:18:15.3271 DEBUG Set System.String value: Norwich
2016-11-08 22:18:15.3428 INFO ================= col 1 
...
2016-11-08 22:18:16.1237 INFO ================= row ==================================
2016-11-08 22:18:16.1394 INFO ================= col 0 
2016-11-08 22:18:16.1394 INFO [0] Item: sChildFoo
2016-11-08 22:18:16.1551 INFO [0] Value: Waterford
2016-11-08 22:18:16.1551 INFO theProp.DeclaringType.FullName of attr: DynamicEFLoading.Child
2016-11-08 22:18:16.1551 INFO theProp.GetSetMethod(true).ToString() of attr: Void set_sChildFoo(System.String)
2016-11-08 22:18:16.1707 INFO theProp.GetType().ToString() of attr: System.Reflection.RuntimePropertyInfo
2016-11-08 22:18:16.1863 INFO theProp.Name of attr: sChildFoo
2016-11-08 22:18:16.1863 INFO theProp.PropertyType.ToString() of attr: System.String
2016-11-08 22:18:16.1863 INFO theProp.ReflectedType.ToString() of attr: DynamicEFLoading.Child
2016-11-08 22:18:16.2020 INFO theProp.ReflectedType.ToString() of attr: System.Void
2016-11-08 22:18:16.2020 DEBUG Set System.String value: Waterford
2016-11-08 22:18:16.2179 INFO ================= col 1 
...
2016-11-08 22:18:16.5772 INFO ================= col 5 
2016-11-08 22:18:16.5772 INFO [5] Item: PersonName
2016-11-08 22:18:16.5772 INFO [5] Value: Barney Rubble
2016-11-08 22:18:16.5772 INFO theProp.DeclaringType.FullName of attr: DynamicEFLoading.Person
2016-11-08 22:18:16.5927 INFO theProp.GetSetMethod(true).ToString() of attr: Void set_PersonName(System.String)
2016-11-08 22:18:16.5927 INFO theProp.GetType().ToString() of attr: System.Reflection.RuntimePropertyInfo
2016-11-08 22:18:16.5927 INFO theProp.Name of attr: PersonName
2016-11-08 22:18:16.6084 INFO theProp.PropertyType.ToString() of attr: System.String
2016-11-08 22:18:16.6084 INFO theProp.ReflectedType.ToString() of attr: DynamicEFLoading.Child
2016-11-08 22:18:16.6240 INFO theProp.ReflectedType.ToString() of attr: System.Void
2016-11-08 22:18:16.6240 DEBUG Set System.String value: Barney Rubble
2016-11-08 22:18:16.6397 INFO end... took 2.391686 seconds.

加载文件、将其解析为 DataSet/DataTable、然后将它们转换为类和 EF 实例、检查每一列的有效性需要 2.4 秒。一切都在 Linux 笔记本电脑上的 Win10 VM 中。

现在,我为您提供(我的混乱且低效的)解决方案来获取和保存 EF 数据,而无需对 Excel 模板的标题行以外的任何内容进行硬编码。

To-Dos:
-添加循环遍历工作簿,执行所有工作表。
-添加验证数据表中指示的类实际上存在于 EF 中(我在我的试点代码中执行此操作)。
-添加在导入之前验证文件是有效的.xlsx文件(Spire有此功能)等。

我花了很多时间来让它工作,而且由于我的正常编程超出了我的能力范围,我将不胜感激任何关于使它更好/更安全等的反馈。我主要是通过翻阅智能感知和书籍来做到这一点的。

=================================================== ===============

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态数据表到实体*无需*提前进行硬编码...? 的相关文章

随机推荐

  • 机器学习回归模型预测每张图像的相同值

    我目前正在开展一个项目 涉及训练回归模型 保存它 然后加载它以使用该模型进行进一步的预测 但是我有一个问题 每次我对图像进行 model predict 时 它都会给出相同的预测 我不完全确定问题是什么 也许是在训练阶段 或者我只是做错了什
  • WPF8/C# - 将数据绑定到网格

    我知道我发布了这个问题 但是在接受了上一个问题的答案并阅读本文后 我意识到这不是我正在寻找的答案 我再次发布了一些示例代码 我想用集合中的数据填充网格 不是数据网格 这是我所拥有的 但它不起作用 如果我删除集合并将 DataContext
  • GridLayoutManager 自定义

    i want to know if there is way that i can customize gridlayoutmanager in android to have horizontal layout like this ske
  • Jquery UI 对话框追加到 Div

    我正在使用下面的代码创建一个 Jquery UI 对话框 var dynDiv document createElement div document getElementById divparent appendChild dynDiv
  • 传递不同类型的可变数量的参数 - C++

    我正在使用 C 进行编码 并且有一些关于省略号的问题 是否可以将类或类指针传递到省略号中 基本上我想做的是以以下类型传递可变数量的参数char and class 我目前正在使用省略号 并试图找出如何通过课堂 如果省略号在这里不适用 有哪些
  • 跨不同域和不同应用程序共享 cookie(经典 ASP 和 ASP.NET)

    有没有办法跨不同域和不同应用程序 经典 ASP 和 ASP NET 共享 cookie 不 没有 问题是跨域问题 而不是 asp net classic asp 并且是安全原因 如果域是子域 您可以共享 cookie 前提是您使用双方都可以
  • VSCode 中 jupyter 笔记本中的交互式 python 3d 绘图

    When I use jupyter notebook in Chrome I had the opportunity to show interactive 3d plots like this 现在我想在 VSCode 中看到相同的结果
  • 如何使用 keycloak 和 spring 读取所有用户?

    我在用着keycloak 3 4 and spring boot开发一个网络应用程序 我使用 Active Directory 作为用户联合来检索所有用户信息 但要在我的网络应用程序中使用这些信息 我想我必须将它们保存在 local web
  • 多级页表——分层分页

    过去操作系统期末考试的示例问题 我如何计算此类问题 计算机有 64 位虚拟地址空间和 2048 字节页面 一个页表项占用 4 个字节 使用多级页表是因为每个表必须包含在一个页内 需要多少级 我该如何计算这个 由于页表必须适合一个页面 因此页
  • 更改分割线突出显示/调整线条大小

    我注意到 当我在 Visual Studio 中调整元素大小时 分割线会被涂成纯透明的黑色 如下所示 然而 在我自己的 Winforms 应用程序中 我得到了以下调整大小行 我想知道如何改变这条调整线的绘画 如果你看一下分离器源代码 htt
  • Firebase 身份验证 FirebaseNetworkException:发生网络错误(例如超时、连接中断或无法访问主机)

    我正在为我的 Android 应用程序创建身份验证工作流程 我允许用户使用用户名 密码和各种 OAuth 提供商登录 我正在验证电子邮件和密码 以便我知道传递给 Firebase 的信息是有效的 我在用着com google firebas
  • 获取 boto.cfg 中的 Python 凭据文件

    我是第一次使用 AWS 刚刚安装了 python 的 boto 我陷入了它建议的步骤 您可以将此文件放置在 etc boto cfg 中供系统范围使用 也可以放置在执行命令的用户的主目录中 boto 老实说 我不知道该怎么办 首先 我找不到
  • 使用 newID() 创建函数

    我不断收到此错误 有什么想法吗 在函数内的 newid 中无效使用副作用或时间相关运算符 我正在与MS SQL Server 2005 这里是T SQL陈述 Create Function dbo GetNewNumber RETURNS
  • 触发多事件

    我可以在trigger 中触发多个事件或在JQuery 中链接它们吗 例如 element trigger event1 event2 event3 or element trigger event1 trigger event2 or e
  • =~ 在 Perl 中做什么?

    我猜标签是一个变量 它正在检查9eaf 但这在 Perl 中存在吗 这里的 符号是做什么的 前后的 字符是什么9eaf doing if tag 9eaf Do something 是测试正则表达式匹配的运算符 表达方式 9eaf 是一个正
  • 什么都没有,WithEvents 字段和内存泄漏

    是否需要设置为Nothing 在 Dispose 中 所有WithEvents fields 显然Handles关键字将处理程序添加到此类字段 但不会将其删除 直到该字段不再存在为止 Nothing 这会产生内存泄漏 这对于像这样的情况应该
  • fork() 后处理子进程中 std::thread 终止的正确方法

    你想皱多少皱眉就皱多少 无论如何我都会这么做 我的问题是 在下面的代码中 处理终止的正确方法是什么std thread在生成的子进程中fork std thread detach or std thread join include
  • 如何在 Rails 1.2.3 中使复选框默认为“选中”?

    如何使复选框在最初显示时默认为 选中 我还没有找到一种 Rails 方法来做到这一点 有效 所以我用 JavaScript 做到了 Rails 有没有正确的方法来做到这一点 我正在使用 Rails 1 2 3 导轨 3 x form for
  • 在 Android 上刷新地图活动中的覆盖对象

    我必须构建一个地图活动 最重要的是 我需要显示一些位置点 这些位置是从另一个类的哈希表中检索的 该哈希表的内容始终会发生变化 因此 我希望看到地图活动上的这些位置点随着哈希表的修改而移动 代码如下所示 Override public voi
  • 动态数据表到实体*无需*提前进行硬编码...?

    问题 问 为什么不能 如何动态使用 DataTable 中的数据在使用反射 的函数中创建 LINQ EF 以根据可用内容创建实体实例 我看到了很多很多的问题和关于硬编码 但没有人这样做动态地 我正在寻找一种替代方法 不必为我的所有实体维护硬