通过反射解析 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 日:初始发布




