Dynamically adjust Create Table and Insert Into st

2019-08-04 11:08发布

问题:

All right, this is the bigger question linked to this link which I tried to delete but couldnt any more. People said I should never post part of the problem due to the x y problem link, which is fair enough. So here it comes.

Lets say I have a class:

 public class CustomClass
{
    public string Year;
    public double val;
    public string Tariff;
    public string ReportingGroup;
}

I now have some process that creates a list of this class with results (in reality its a bigger class but that shouldnt matter).

I now create an Access table if it doesnt exist yet. For this I need the class members and ideally also the type (currently all text!):

public static void createtable(string path, string tablename, string[] columnnames)
    {
        try
        {
            string connectionstring = creadteconnectionstring(path);
            OleDbConnection myConnection = new OleDbConnection(connectionstring);
            myConnection.Open();
            OleDbCommand myCommand = new OleDbCommand();
            myCommand.Connection = myConnection;
            string columnam = "[" + columnnames[0] + "] Text";

            for (int i = 1; i < columnnames.Length; i++)
            {
                    columnam = columnam + ", [" + columnnames[i] + "] Text";
            }

            myCommand.CommandText = "CREATE TABLE [" + tablename + "](" + columnam + ")";
            myCommand.ExecuteNonQuery();
            myCommand.Connection.Close();
            Console.WriteLine("Access table " + tablename + " created.");
        }
        catch 
        {
                Console.WriteLine("Access table " + tablename + " already exists.");
                return;


        }


    }

Note column name contains actually the names of the class members of custom class. Then I paste the data into it:

        public static void appenddatatotable(string connectionstring, string tablename, string datstr, List<CustomClass> values)
    {
        string commandtext = "INSERT INTO " + tablename + " ([RunDate],[ReportingGroup], [Tariff], [Year], [Quarter]) VALUES(@RunDate, @ReportingGroup, @Tariff, @Year, @Quarter)";
        using (var myconn = new OleDbConnection(connectionstring))
        {
            myconn.Open();
            using (var cmd = new OleDbCommand())
            {

                foreach (var item in values)
                {
                    cmd.CommandText = commandtext;
                    if (string.IsNullOrEmpty(item.val))
                        item.val = "";
                    cmd.Parameters.Clear();
                    cmd.Parameters.AddRange(new[] { new OleDbParameter("@RunDate", datstr), new OleDbParameter("@ReportingGroup", item.RG), new OleDbParameter("@Tariff", item.tar), new OleDbParameter("@Year", item.yr), new OleDbParameter("@Quarter", item.val)});
                    cmd.Connection = myconn;
                    //cmd.Prepare();
                    cmd.ExecuteNonQuery();

                }
            }
        }

    }

This all works fine.

However, say I change sth in my process that also needs another calculation that yields value2, then I need to change the class, the createtable and teh appenddatatotable function. I would like to only update the class.

回答1:

So, you are trying to build your own ORM (Object Relational Mapper) for C# and MS Access databases.
While this is an interesting endeavour as a learning experience, it's a problem that is hard to tackle properly.

What you need to do is use reflection in your createtable to determine the details metadata necessary (property names, property types) to construct the CREATE TABLE SQL Statement.
Then you could use something like DBUtils.CreateTable<CustomClass>(connStr); to create the table.

Since you have not mentioned reflection in this question, you really need to first learn as much as you can about it, and experiment with it first before you can answer your own question.
You previous question had some answers that already mentioned using reflection and showed you how to get the property names and types of arbitrary classes.

Once you get through that hurdle, you will encounter other problems:

  • How to define type lengths
    Especially for strings, in .Net they can be considered almost unlimited (for most use anyway) but in Access, a string of less than 255 characters is not the same type as a larger one.

  • How to define your Primary key.
    As a general rule, all tables in a database must have a Primary Key field that is used to identify each record in a table in a unique way.
    In an ORM, it's really important, so you can easily fetch data based on that key, like GetByID<CustomClass>(123) would return an instance of your CustomClass that contains the data from record whose primary key ID is 123.

  • How to define indexes in your database.
    Creating tables is all good and well, but you must be able to define indexes so that queries will have expected performance.

  • How to define relationships between tables.
    Databases are all about relational data, so you need a way to define these relationships within your classes so that a class PurchaseOrder can have a list of PurchaseItem and your code understand that relationship, for instance when you need to delete a given Purchase Order, you will also need to delete all of its items in the database.

  • How to only load what you need.
    Say you have a Customer class that has a PurchaseOrders property that is in fact a List<PurchaseOrders>. Now, if you load the data of a particular customer, to display their phone number for instance, you do not want to also pull all the possible 1,000s or orders they have made over the years, each of these having maybe 100s of items...

  • How to execute queries and use their results.
    Once you have mapped all your tables to classes, how do you query your data?
    linq is fantastic, but it's very hard to implement by yourself, so you need a good solution to allow you to make queries and allow your queries to return typed data.

For many of these issues, custom Attributes are the way to go, but as you move along and make your ORM more powerful and flexible, it will increase in complexity, and your early decisions will sometimes weigh you down and complicate things further because, let's face it, building an ORM from scratch, while an interesting experience, is hard.

So, you really have to think about all these questions and set yourself some limits on what you need/want from the system before jumping into the rabbit hole.