通过反射解析 DataSet
本文展示了如何将关系数据模型与对象设计模型绑定。

引言
很多时候,我需要将关系模型与对象设计模型绑定。有时,我使用 NHibernate 创建应用程序引擎,有时我使用 ADO.NET Entity Framework,但大多数情况下我不得不使用 DataTable
并围绕 DataTable
对象创建包装器,其中包含大量的 "switch
" 语句。
NHibernate 在开发 "桌面" 或 "Web" 应用程序时是一个不错的选择,但它在 Windows Mobile 上的 Compact Framework 中无法工作,因为 CF 不支持动态编译。 ADO.NET Entity Framework 是为 .NET 3.5 风格设计的 "新" 应用程序的一个不错的选择。 在本文中,我想展示如何解析 DataSet
并从中创建对象。 您可以从本文顶部的链接下载源代码并使用这个小库。
背景
要测试应用程序,您应该安装 SQL Compact 3.5 和 .NET 3.5。 您也可以在 .NET 2.0 中使用此库,但您应该替换 LINQ 用法。
Using the Code
为了展示它的工作原理,我创建了一个包含 3 个表的简单数据库。 该系统的核心是泛型类 BusinessObject<T>
。 该类包含必要的 static
方法,允许获取派生对象。
public static List<T> Get(DataSet dataSet)
public static List<T> Get(DataTable dataTable)
public static T GetOne(DataSet dataSet)
public static T GetOne(DataTable dataTable)
public static T GetOne(DataRow row)
绑定对象的步骤
- 创建一个从
BusinessObject<T>
派生的新类。 - 创建与数据库字段对应的属性,并使用 "
BoFieldAttribute
" 标记它们。 - 如果表与其他表有关系,则创建新的属性并使用
BoChildAttribute
标记它们。
BoFieldAttribute
- 具有带参数 "name
" 的构造函数。 您应该放置一个与 DataTable
中的 ColumnName
对应的 string
。
这是一个例子。
class Customer : BusinessObject<Customer>
{
[BoField(CustomerNames.Id)]
public int Id { get; set; }
[BoField(CustomerNames.Name)]
public string Name { get; set; }
}
class Product : BusinessObject<Product>
{
[BoField(ProductNames.Id)]
public int Id { get; set; }
[BoField(ProductNames.Title)]
public string Title { get; set; }
}
class OrderLine : BusinessObject<OrderLine>
{
[BoField(OrderLineNames.Id)]
public int Id { get; set; }
[BoField(OrderLineNames.ProductId)]
public int ProductId { get; set; }
[BoField(OrderLineNames.CustomerId)]
public int CustomerId { get; set; }
[BoChild]
public Customer Customer { get; set; }
[BoChild]
public Product Product { get; set; }
}
然后使用起来非常简单。 只需调用 "Get
" 方法之一即可。
const string sql =
@"SELECT * FROM OrderLine INNER JOIN Customer
ON Customer.C_Id = OrderLine.O_CustomerId
INNER JOIN Product
ON Product.P_Id = OrderLine.O_ProductId";
DataTable dataTable = DatabaseLayer.Instance.ExecuteTable(sql);
lwOrderLines.ItemsSource = OrderLine.Get(dataTable);
工作原理
当您调用 "Get
" 方法之一时
BusinessObject
类创建泛型类型的新对象。- 搜索标记的属性并将新值从
DataTable
分配给属性。
还有一件事我想描述的是 GetConvertedObject
方法
protected virtual object GetConvertedObject(Type type, object o)
{
if (type.IsEnum) return Enum.Parse(type, o.ToString(),true);
if (type == typeof(byte[])) return o.Equals(DBNull.Value) ? null : o;
if (type == typeof(DateTime)) return ToDateTime(o);
if (type == typeof(string)) return ToString(o);
if (type == typeof(int)) return ToInt32(o);
if (type == typeof(long)) return ToInt64(o);
if (type == typeof(DateTime)) return ToDateTime(o);
if (type == typeof(Double)) return ToDouble(o);
if (type == typeof(Boolean))
return o.ToString().Trim() == "1"
? true : o.ToString().Trim() == "0"
? false : type.ParseValue(o);
return type.ParseValue(o);
}
此方法是虚拟的,可以在派生类中重写。 如果我们希望在解析操作中具有转换数据的可能性,它非常有用。 例如,我们可以将数据作为图像类型存储在 SQL Compact 中,并将其转换为 System.Drawing.Image
或 ImageSource
(WPF 版本)。
历史
- 2009 年 9 月 1 日:初始发布