DataTableAdapter





5.00/5 (10投票s)
如何使用适配器模式扁平化 ObjectDataSource 的集合。
引言
这是一个类和示例,说明如何将域模型扁平化为 DataTable
,以便于使用 ObjectDataSource
。
背景
我已经在 WinForms 应用程序中使用 OR/M 建模一段时间了。最近,我需要一个 ASP.NET 应用程序,并且很快对 ObjectDataSource
感到非常沮丧。我不想陷入 DataSet
和集合之间的争论。 可以这么说,我使用强类型集合。
问题
当使用非扁平(分层)域模型时,无法绑定到复杂的属性。例如,在下面的域模型中,我需要在类列表中显示 Instructor
的 FullName
,并随后能够编辑它。但是,虽然我可以绑定到 Instructor
,但它会显示 Person
的 toString()
方法中的任何内容。这对于显示来说很好,但是编辑呢?我可以实现 IConvertible<T>
,但我在表示层之外不需要此功能。因此,让我们使用适配器设计模式将对象集合(或仅单个对象)适配到 DataTable
中。
这种方法还产生了许多其他优点。如果没有大量的管道,ObjectDataSource
就无法很好地排序或分页。当绑定到 DataTable
时,它可以本地处理此问题,因此无需编写额外的代码。
使用代码
由于 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 的博客上找到了这个结果。