将DataRow转换为对象

4

我创建了一个通用的List,然后用一些对象填充它。然后将提到的List转换为DataTable以在DataGridView中使用。问题是当我想从这个表格获取行时,我有了DataRow。我想将其再次转换为我的对象,但不确定如何做。也许你可以给出一些示例呢?

谢谢。


一点代码会很有帮助... - Thomas Levesque
4个回答

11

如果你不能或不想使用“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


谢谢, 如果我需要转换多种类型,我可以使用这个方法(当然需要做一些更改)。例如,一个DataTable包含客户数据记录,另一个包含地址记录。我需要使用反射吗? - arek
当然,您可以使用反射来概括此方法以适用于任何类型,并进一步改善由反射导致的性能下降,您可以使用Reflection.Emit生成动态程序集,然后在集合中添加一些惰性加载。最终,您会了解到人们已经思考过这些问题并发明了ORM,例如NHibernate,Entity Framework等,您会意识到自己已经为已经存在且可以免费使用的东西付出了努力。 - Darin Dimitrov
也许我应该解释一下为什么我不使用EF和其他ORM。我从WS获取一些对象数组,然后用这些项填充网格。将此数组转换为DataTable的唯一原因是我想排序,并发现将其转换为DataTable是提供此功能的好方法,因为有很多示例。 - arek
使用Linq-to-Objects对内存中的数组进行排序非常容易。 - Darin Dimitrov
嗯,我的意思是我想给用户在网格中排序数据的机会。当我用数组填充网格时,我无法做到这一点。 - arek

9
假设您正在使用一个名为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();

1

为什么不直接将对象放入BindingList<>而不是List<>中呢?这样,您就可以跳过将其转换为DataTable再转回来的步骤。您可能需要在对象上实现INotifyPropertyChanged,但一旦它们在BindingList中,数据网格中的更改将自动应用于底层对象。

排序可以通过手动按列标题单击对列表进行排序或通过继承自BindingList<>并在其中实现排序功能来处理 - 然后单击标题会自动对列表进行排序 - 不需要编写代码。


0

现在使用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对象可以绑定许多数据源类型。因此,从设计角度来看,你需要决定选择哪种方式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接