从数据库行创建对象

时间:2008-09-02 18:56:37

标签: .net

假设我正在为应用程序构建数据访问层。通常,我对存储在数据库中的每种对象都有一个类定义。当然,实际数据访问以datareader,类型化或非类型化数据集或类似形式检索数据,通常使用在结果中每行创建一个对象所需的数据。

您将如何在数据层中创建对象实例?会有一个接受数据行的构造函数吗?如果是这样,你会如何使这种类型安全?或者你会让你的构造函数为你要实例化的每个字段列出一个参数,即使可能有很多字段?你会把这个构造函数标记为“内部”吗?

5 个答案:

答案 0 :(得分:7)

如果您不满足于DataRow或SqlDataReader,您应该查看一个ORM系统,如Linq to Sql或nHibernate,而不是自己重新发明轮子。

(顺便说一句,这被称为“ActiveRecord”模式)

答案 1 :(得分:3)

我强烈建议您使用ORM工具。即使是简单的项目也可以快速而安静地使用ORM ......特别是,查看CastleActiveRecord工具(位于NHibernate之上以简化模型声明)。

答案 2 :(得分:2)

我通过使用反射完成了这一点。我从对象的Select语句命名列。

这假设您有一个Templated助手类。如果你想自己把它放在对象上,你可以用对象替换所有T。

这是一个例子:

private T ObjectFromRow(DataRow row)
{
    Type t = typeof(T);

    T newObj = (T)Activator.CreateInstance(t);


    System.Reflection.PropertyInfo[] properties = t.GetProperties();

    for (int i = 0; i < properties.Length; i++)
    {
        if (!properties[i].CanWrite)
        {
            continue;
        }

        if (!row.Table.Columns.Contains(properties[i].Name))
        {
            continue;
        }

        if (row[properties[i].Name] == DBNull.Value)
        {
            continue;
        }

        if (properties[i].PropertyType == typeof(string))
        {
            properties[i].SetValue(newObj, row[properties[i].Name], null);
        }
        else if (properties[i].PropertyType == typeof(double))
        {
            properties[i].SetValue(newObj, double.Parse(row[properties[i].Name].ToString()), null);
        }
        else if (properties[i].PropertyType == typeof(int))
        {
            properties[i].SetValue(newObj, int.Parse(row[properties[i].Name].ToString()), null);
        }
        else if (properties[i].PropertyType == typeof(DateTime))
        {
            properties[i].SetValue(newObj, DateTime.Parse(row[properties[i].Name].ToString()), null);
        }
        else if (properties[i].PropertyType == typeof(bool))
        {
            properties[i].SetValue(newObj, bool.Parse(row[properties[i].Name].ToString()), null);
        }
    }

    return newObj;
}

答案 3 :(得分:1)

@Joel(re:复杂查询,联接等)

NHibernate和Castle ActiveRecord工具可以通过类关系和一个彻底的“表达式”类(可以添加到查询方法中)或使用“Hibernate查询语言”(HQL)来处理非常复杂的查询和连接。

您可以使用Google中的任何一项详细信息,查看官方documentation,或查看精彩的Summer of NHibernate截屏视频。

答案 4 :(得分:1)

作为NHibernate&amp; amp;的替代品城堡你可以看看SubSonic。这也使用ActiveRecord但更像是一把瑞士军刀而不是NHibernate。

编辑:

以下是SubSonic文档中的sample

Simple Select with string columns

            int records = new Select("productID").
                 From("Products").GetRecordCount();

            Assert.IsTrue(records == 77);

Simple Select with typed columns

            int records = new Select(Product.ProductIDColumn, Product.ProductNameColumn).
                From<Product>().GetRecordCount();
            Assert.IsTrue(records == 77);

还有一些examples

Standard Deviation

    const double expected = 42.7698669325723;

    // overload #1
    double result = new
        Select(Aggregate.StandardDeviation("UnitPrice"))
        .From(Product.Schema)
        .ExecuteScalar<double>();
    Assert.AreEqual(expected, result);

    // overload #2
    result = new
        Select(Aggregate.StandardDeviation(Product.UnitPriceColumn))
        .From(Product.Schema)
        .ExecuteScalar<double>();
    Assert.AreEqual(expected, result);

    // overload #3
    result = new
        Select(Aggregate.StandardDeviation("UnitPrice", "CheapestProduct"))
        .From(Product.Schema)
        .ExecuteScalar<double>();
    Assert.AreEqual(expected, result);

    // overload #4
    result = new
        Select(Aggregate.StandardDeviation(Product.UnitPriceColumn, "CheapestProduct"))
        .From(Product.Schema)
        .ExecuteScalar<double>();
    Assert.AreEqual(expected, result);

还有一些Wildcard methods

 [Test]
        public void Select_Using_StartsWith_C_ShouldReturn_9_Records() {


            int records = new Select().From<Product>()
                .Where(Northwind.Product.ProductNameColumn).StartsWith("c")
                .GetRecordCount();
            Assert.AreEqual(9, records);
        }