65.9K
CodeProject 正在变化。 阅读更多。
Home

DataTableAdapter

starIconstarIconstarIconstarIconstarIcon

5.00/5 (10投票s)

2006年11月4日

CPOL

2分钟阅读

viewsIcon

74608

downloadIcon

376

如何使用适配器模式扁平化 ObjectDataSource 的集合。

引言

这是一个类和示例,说明如何将域模型扁平化为 DataTable,以便于使用 ObjectDataSource

背景

我已经在 WinForms 应用程序中使用 OR/M 建模一段时间了。最近,我需要一个 ASP.NET 应用程序,并且很快对 ObjectDataSource 感到非常沮丧。我不想陷入 DataSet 和集合之间的争论。 可以这么说,我使用强类型集合。

问题

当使用非扁平(分层)域模型时,无法绑定到复杂的属性。例如,在下面的域模型中,我需要在类列表中显示 InstructorFullName,并随后能够编辑它。但是,虽然我可以绑定到 Instructor,但它会显示 PersontoString() 方法中的任何内容。这对于显示来说很好,但是编辑呢?我可以实现 IConvertible<T>,但我在表示层之外不需要此功能。因此,让我们使用适配器设计模式将对象集合(或仅单个对象)适配到 DataTable 中。

这种方法还产生了许多其他优点。如果没有大量的管道,ObjectDataSource 就无法很好地排序或分页。当绑定到 DataTable 时,它可以本地处理此问题,因此无需编写额外的代码。

DataStore.png

使用代码

由于 Course 没有显示属性“InstructorId”、“InstructorFullName”或“AvailableSlots”,我们可以基本上将它们混合到数据类型中,就好像它们是类的一部分一样。 像 Ruby 和 Python 这样的动态语言允许在对象级别执行此操作,从而无需在转换中执行此操作。 C#3(和 VB9)有一种叫做扩展方法的东西,但到目前为止还没有提到扩展属性(这是数据绑定所需要的)。

[DataObjectMethod(DataObjectMethodType.Select)]
public static DataTable FindAll()
{
    DataTableAdapter<Course> dta = new DataTableAdapter<Course>();
    dta.AddColumn("InstructorId", typeof(string), 
        delegate(Course c) { return c.Instructor.Id; });
    dta.AddColumn("InstructorFullName", typeof(string), 
        delegate(Course c) { return c.Instructor.FullName; });
    dta.AddColumn("AvailableSlots", typeof(string), 
        delegate(Course c) { return c.MaxStudents - c.Students.Count; });
    return dta.GetDataTable(CourseService.FindAll());
}

潜在问题

显然,这里大量使用了反射。 根据正在使用的对象库的大小,这可能会导致一些性能问题。

来源

DataTableAdapter 的完整源代码位于 App_Code 文件夹下的 DataTableAdapter.cs 中。它有很好的注释并且相当不言自明。我想指出我必须搜索的部分。它与检测可空类型然后获取其底层类型有关。之所以需要这样做,是因为 DataTable 不会接受列定义中的可空类型。它为此值使用 DBNull。无论如何,这是一个摘录...

//Get all the pi's once.

PropertyInfo[] pi = typeof(T).GetProperties();

Type piType;
//Add all the properties as columns

for (int i = 0; i < pi.Length; i++)
{
    piType = pi[i].PropertyType;

    //Data tables don't accept nullables in the column type.  Therefore,

    //when we encounter a nullable, we need to get it's underlying type.

    if (piType.IsGenericType && 
           piType.GetGenericTypeDefinition() == typeof(Nullable<>))
        piType = Nullable.GetUnderlyingType(piType);

    dt.Columns.Add(new DataColumn(pi[i].Name, piType));
}

参考文献

这个想法来自 Google 搜索,它在 Brendan Tompkin 的博客上找到了这个结果

© . All rights reserved.