1

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.

4

1 回答 1

2

因此,您正在尝试为 C# 和 MS Access 数据库构建自己的 ORM(对象关系映射器)。
虽然这是一种有趣的学习体验,但它是一个很难正确解决的问题。

您需要做的是使用反射createtable来确定构建CREATE TABLESQL 语句所需的详细元数据(属性名称、属性类型)。
然后你可以使用类似的东西DBUtils.CreateTable<CustomClass>(connStr);来创建表。

由于您在这个问题中没有提到反射,因此您确实需要首先尽可能多地了解它,并先进行试验,然后才能回答自己的问题。
您之前的问题有一些已经使用反射提到的答案,并向您展示了如何获取任意类的属性名称和类型。

一旦你通过了这个障碍,你会遇到其他问题:

  • 如何定义类型长度
    特别是对于字符串,在 .Net 中它们几乎可以被认为是无限的(无论如何大多数使用),但在 Access 中,少于 255 个字符的字符串与较大的字符串类型不同。

  • 如何定义您的主键。
    作为一般规则,数据库中的所有表都必须有一个主键字段,用于以唯一的方式标识表中的每条记录。
    在 ORM 中,它非常重要,因此您可以轻松地根据该键获取数据,例如GetByID<CustomClass>(123)返回一个CustomClass包含主键ID为 123 的记录中的数据的实例。

  • 如何在数据库中定义索引。
    创建表很好,但您必须能够定义索引,以便查询具有预期的性能。

  • 如何定义表之间的关系。
    数据库都是关于关系数据的,因此您需要一种在类中定义这些关系的方法,以便类PurchaseOrder可以有一个列表PurchaseItem并且您的代码可以理解这种关系,例如,当您需要删除给定的采购订单时,您还将需要删除它在数据库中的所有项目。

  • 如何仅加载您需要的内容。
    假设您有一个 Customer 类,它的PurchaseOrders属性实际上是List<PurchaseOrders>. 现在,如果您加载特定客户的数据,例如显示他们的电话号码,您不希望同时提取他们多年来下的所有可能的 1,000 件或订单,每个订单可能有 100 件商品。 ..

  • 如何执行查询并使用其结果。
    将所有表映射到类后,如何查询数据?
    linq 很棒,但是自己很难实现,所以你需要一个好的解决方案来允许你进行查询并允许你的查询返回类型化的数据。

对于这些问题中的许多问题,自定义属性是可行的方法,但是随着您继续前进并使您的 ORM 更加强大和灵活,它会增加复杂性,并且您的早期决定有时会使您感到沮丧并使事情变得更加复杂,因为,让我们面对现实,从头开始构建 ORM 虽然是一种有趣的体验,但很难。

所以,在跳进兔子洞之前,你真的必须考虑所有这些问题,并为自己需要/想要从系统中获得什么设置一些限制。

于 2013-09-07T08:47:41.153 回答