C# 将 DataRow 转换为对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1709596/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 20:10:04  来源:igfitidea点击:

Convert DataRow to object

c#.net

提问by arek

I've created generic List and populate with some objects. Then List I mentioned before converted into DataTable to use in DataGridView. Problem is when I want get Row from this grid I have DataRow. I wanted to convert this to my object againt but not sure how to do it. Maybe you could give some example?

我创建了通用列表并填充了一些对象。然后我之前提到的List转换成DataTable在DataGridView中使用。问题是当我想从这个网格中获取 Row 时,我有 DataRow。我想再次将其转换为我的对象,但不知道该怎么做。也许你可以举一些例子?

Thanks

谢谢

回答by Thomas Levesque

Assuming you're using a class MyObject, defined as follows :

假设您使用的是 class MyObject,定义如下:

class MyObject
{
    public string Foo { get; set; }
    public int Foo { get; set; }
}

You could do something like that :

你可以这样做:

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();

回答by marc_s

Well, if you can't or won't use an "ORM" (object-relational mapper, like Linq-to-SQL or NHibernate - that's exactly what these tools do, and do quite well for you), you'll have to do this yourself.

好吧,如果您不能或不会使用“ORM”(对象关系映射器,如 Linq-to-SQL 或 NHibernate - 这正是这些工具所做的,并且为您做得很好),您将拥有自己做。

Converting a DataRow into a domain object model is pretty boring code, really:

将 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;
}

The biggest challenge here is making this rock-solid and handling (or avoiding) all possible errors (like a field being NULL etc.).

这里最大的挑战是使这个坚如磐石并处理(或避免)所有可能的错误(如字段为 NULL 等)。

Another possibility would be to have a constructor on your domain model object type that would take a DataRowas parameter and construct a new object from it.

另一种可能性是在域模型对象类型上有一个构造函数,它将 aDataRow作为参数并从中构造一个新对象。

Marc

马克

回答by Zack

Why not just put your objects into a BindingList<> rather than a List<>? Then you can skip the converting to DataTable and back again exercise. You may need to implement INotifyPropertyChangedon your objects, but once they are inside a BindingList, changes in the datagrid will automatically be applied to your underlying objects.

为什么不直接将对象放入 BindingList<> 而不是 List<> 中?然后您可以跳过转换为 DataTable 并再次返回练习。您可能需要在您的对象上实现INotifyPropertyChanged,但是一旦它们位于 BindingList 中,数据网格中的更改将自动应用于您的底层对象。

Sorting can be handled by either sorting the list manually on column header click, or by inheriting from BindingList<> and implementing the sorting functionality inside it - then clicking on a header automatically sorts the list - no code required.

排序可以通过在单击列标题时手动对列表进行排序来处理,也可以通过从 BindingList<> 继承并在其中实现排序功能来处理 - 然后单击标题自动对列表进行排序 - 无需代码。

回答by YeinCM-Qva

Well nowadays it is easier using ORMs of course. But if still you're using the old fashion you can go with a pretty easy Extension Class to do the job for you using a little bit of reflection and generic methods and lambda as follows:

现在当然使用 ORM 更容易。但是如果你仍然使用旧的方式,你可以使用一个非常简单的扩展类来为你完成这项工作,使用一些反射和泛型方法以及 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;
            }
        }
}

You should also remember GridView objects can bind a lot of data source types. So it is your decision from a design point about what you should go with.

您还应该记住 GridView 对象可以绑定很多数据源类型。因此,您应该从设计角度决定应该采用什么。