从数据库行创建对象
假设我正在为应用程序构建数据访问层。通常,我为存储在数据库中的每种对象都有一个类定义。当然,实际的数据访问以数据读取器,输入或不输入数据集的形式或类似方式检索数据,通常与结果中每行创建一个对象所需的数据相关。从数据库行创建对象
你将如何去创建数据层中的对象实例?会有一个接受数据行的构造函数?如果是这样,你会如何使这种类型安全?或者你是否想让你的构造函数列出你想要实例化的每个字段的一个参数,即使可能有很多字段?你会将这个构造函数标记为“内部”吗?
如果您对DataRow或SqlDataReader不满意,您应该查看ORM系统,如Linq to Sql或nHibernate,而不是自己重新发明*。
(顺便说一句,这就是所谓的“ActiveRecord的”模式)
这些支持更复杂的查询作为数据源吗?例如,即使仅仅确定在特定情况下应该返回哪些记录,也可以加入其他几张表中。他们会让你将自己的方法添加到他们使用的类中吗?
我已经完成了这个通过使用反射。我在哪里命名对象的Select语句中的列。
这假定你有一个模板帮助类。如果你想自己把它放在物体上,你可以用物体代替所有的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;
}
@Joel(RE:复杂的查询,连接等)
的NHibernate和ActiveRecord的城堡工具可以处理非常复杂的查询,并通过阶级关系和加入彻底的'表达'类(您可以添加到查询方法中)或使用'Hibernate查询语言'(HQL)。
你可以谷歌任何这些细节,检查官方documentation,或看到真棒Summer of NHibernate截屏视频。
作为NHibernate的替代品&城堡,你可以看看SubSonic。这也使用ActiveRecord,但比NHibernate更像是瑞士军刀。
编辑:
下面是从亚音速文档一个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);
}