我创建了一个通用的List,然后用一些对象填充它。然后将提到的List转换为DataTable以在DataGridView中使用。问题是当我想从这个表格获取行时,我有了DataRow。我想将其再次转换为我的对象,但不确定如何做。也许你可以给出一些示例呢?
谢谢。
如果你不能或不想使用“ORM”(对象关系映射器,例如 Linq-to-SQL 或 NHibernate - 这正是这些工具所做的,并且为您提供了非常好的支持),那么你将不得不自己实现。
将 DataRow 转换为领域对象模型实际上是相当无聊的代码:
public Customer ConvertRowToCustomer(DataRow row)
{
Customer result = new Customer();
result.ID = row.Field<int>("ID");
result.Name = row.Field<string>("CustomerName");
..... // and so on
return result;
}
在这里最大的挑战是要使它坚如磐石,并处理(或避免)所有可能的错误(例如字段为空等)。
另一个可能性是在您的域模型对象类型上具有一个构造函数,该函数将采用 DataRow
作为参数并从中构造出一个新对象。
Marc
MyObject
的类,其定义如下:class MyObject
{
public string Foo { get; set; }
public int Foo { get; set; }
}
您可以这样操作:
using System.Data.DataSetExtensions;
...
List<MyObject> list = (from row in table.AsEnumerable()
select new MyObject
{
Foo = row.Field<string>("foo"),
Bar = row.Field<int>("bar")
}).ToList();
为什么不直接将对象放入BindingList<>而不是List<>中呢?这样,您就可以跳过将其转换为DataTable再转回来的步骤。您可能需要在对象上实现INotifyPropertyChanged,但一旦它们在BindingList中,数据网格中的更改将自动应用于底层对象。
排序可以通过手动按列标题单击对列表进行排序或通过继承自BindingList<>并在其中实现排序功能来处理 - 然后单击标题会自动对列表进行排序 - 不需要编写代码。
现在使用ORMs当然更容易了。但是如果你仍然使用旧的方式,你可以使用一个非常简单的扩展类来完成工作,只需要使用一点反射和泛型方法以及lambda表达式,如下所示:
public static class MapperExtensionClass
{
public static IEnumerable<MyClassType> ToMyClassTypeEnumerable(this DataTable table)
{
return table.AsEnumerable().Select(r => r.ToMyClassType());
}
public static MyClassType ToMyClassType(this DataRow row)
{
return row.ToObject<MyClassType>();
}
public static T ToObject<T>(this DataRow row) where T: new()
{
T obj = new T();
foreach (PropertyInfo property in typeof(T).GetProperties())
{
if (row.Table.Columns.Contains(property.Name))
{
property.SetValue(obj, property.PropertyType.ToDefault(row[property.Name]));
}
}
return obj;
}
public static object ToDefault(this Type type, object obj)
{
if (type == null)
throw new Exception("Customized exception message");
var method = typeof(MapperExtensionClass)
.GetMethod("ToDefaultGeneric", BindingFlags.Static | BindingFlags.Public);
var generic = method.MakeGenericMethod(type);
return generic.Invoke(null, new object[] { obj });
}
public static T ToDefaultGeneric<T>(object obj)
{
if (obj == null || obj == DBNull.Value)
{
return default(T);
}
else
{
return (T)obj;
}
}
}
你还应该记住,GridView对象可以绑定许多数据源类型。因此,从设计角度来看,你需要决定选择哪种方式。