C# 如何将 DataRow 转换为对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19673502/
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-10 15:35:19  来源:igfitidea点击:

How to Convert DataRow to an Object

c#objectdatarow

提问by folk

I created a DataRow on my project:

我在我的项目中创建了一个 DataRow:

DataRow datarow;

I want to convert this DataRow to any Type of Object. How could I do it?

我想将此 DataRow 转换为任何类型的对象。我怎么能做到?

回答by Avi Fatal

class Person{
public string FirstName{get;set;}
public string LastName{get;set;}
}

Person person = new Person();
person.FirstName = dataRow["FirstName"] ;
person.LastName = dataRow["LastName"] ;

or

或者

Person person = new Person();
person.FirstName = dataRow.Field<string>("FirstName");
person.LastName = dataRow.Field<string>("LastName");

回答by IDeveloper

DataRow has a property ItemArray, which contains an array of object values. You can work with this array and create any custom type with the values from your DataRow.

DataRow 有一个属性 ItemArray,它包含一个对象值数组。您可以使用此数组并使用 DataRow 中的值创建任何自定义类型。

回答by Corey

Apart from the manual method Avi shows, you can use a mapping system like AutoMapperto do the transformation for you. This is particularly useful in the case where you have a lot of columns/properties to map.

除了 Avi 显示的手动方法外,您还可以使用AutoMapper 之类的映射系统为您进行转换。这在您有很多要映射的列/属性的情况下特别有用。

Check out this articleon how to use AutoMapper to convert a DataTableto a list of objects.

看看这篇文章关于如何使用AutoMapper到转换DataTable到对象的列表。

回答by Thilina H

Given Converter<TIn, TOut>is a delegate, then the following should work:

鉴于Converter<TIn, TOut>是一个委托,那么以下应该工作:

List<Person> personList = new List<Person>();

personList = ConvertDataRowToList(ds, (row) => {
    return new Person
    {
        FirstName = row["FirstName"],
        LastName  = row["LastName"]
        // Rest of properties should assign here...
    };
});

https://docs.microsoft.com/en-us/dotnet/api/system.converter-2

https://docs.microsoft.com/en-us/dotnet/api/system.converter-2

回答by Bharat

I Have found one solution for my application.

我为我的应用找到了一种解决方案。

    // function that creates an object from the given data row
    public static T CreateItemFromRow<T>(DataRow row) where T : new()
    {
        // create a new object
        T item = new T();

        // set the item
        SetItemFromRow(item, row);

        // return 
        return item;
    }

    public static void SetItemFromRow<T>(T item, DataRow row) where T : new()
    {
        // go through each column
        foreach (DataColumn c in row.Table.Columns)
        {
            // find the property for the column
            PropertyInfo p = item.GetType().GetProperty(c.ColumnName);

            // if exists, set the value
            if (p != null && row[c] != DBNull.Value)
            {
                p.SetValue(item, row[c], null);
            }
        }
    }

This will map your DataRowto ViewModel, Like below.

这会将您的DataRow映射到ViewModel,如下所示。

Your_ViewModel model = CreateItemFromRow<Your_ViewModel>(row);

回答by Daniel Carvalho Liedke

With these changes worked fine for me, for fields int, long, int? and long?

这些更改对我来说效果很好,对于字段 int、long、int?和长?

// function that creates an object from the given data row
public static T CreateItemFromRow<T>(DataRow row) where T : new()
{
    // create a new object
    T item = new T();

    // set the item
    SetItemFromRow(item, row);

    // return 
    return item;
}

public static void SetItemFromRow<T>(T item, DataRow row) where T : new()
{
    // go through each column
    foreach (DataColumn c in row.Table.Columns)
    {
        // find the property for the column
        PropertyInfo p = item.GetType().GetProperty(c.ColumnName);

        // if exists, set the value
        if (p != null && row[c] != DBNull.Value)
        {
            if (p.PropertyType.Name == "Int64")
            {
                p.SetValue(item, long.Parse(row[c].ToString()), null);
            }
            else if (p.PropertyType.Name == "Int32")
            {
                p.SetValue(item, int.Parse(row[c].ToString()), null);
            }
            else if (p.PropertyType.FullName.StartsWith("System.Nullable`1[[System.Int32"))
            {
                p.SetValue(item, (int?)int.Parse(row[c].ToString()), null);
            }
            else if (p.PropertyType.FullName.StartsWith("System.Nullable`1[[System.Int64"))
            {
                p.SetValue(item, (long?)long.Parse(row[c].ToString()), null);
            }
            else
            {
                p.SetValue(item, row[c], null);
            }
        }
    }
}

回答by Jonathan Santiago

This is a pretty cool way I use it.

这是我使用它的一种非常酷的方式。

    public static T ToObject<T>(this DataRow dataRow)
    where T : new()
    {
        T item = new T();

        foreach (DataColumn column in dataRow.Table.Columns)
        {
            PropertyInfo property = GetProperty(typeof(T), column.ColumnName);

            if (property != null && dataRow[column] != DBNull.Value && dataRow[column].ToString() != "NULL")
            {
                property.SetValue(item, ChangeType(dataRow[column], property.PropertyType), null);
            }
        }

        return item;
    }

    private static PropertyInfo GetProperty(Type type, string attributeName)
    {
        PropertyInfo property = type.GetProperty(attributeName);

        if (property != null)
        {
            return property;
        }

        return type.GetProperties()
             .Where(p => p.IsDefined(typeof(DisplayAttribute), false) && p.GetCustomAttributes(typeof(DisplayAttribute), false).Cast<DisplayAttribute>().Single().Name == attributeName)
             .FirstOrDefault();
    }

    public static object ChangeType(object value, Type type)
    {
        if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
        {
            if (value == null)
            {
                return null;
            }

            return Convert.ChangeType(value, Nullable.GetUnderlyingType(type));
        }

        return Convert.ChangeType(value, type);
    }

回答by Nashe

Similar to some of the previous approaches, I created this extension method for DataRowwhich takes an argument object to be populated. Main difference is that in addition to populating object's Properties, it also populates Fields of given object. This should also work for simpler structures (Though I only tested on objects).

与之前的一些方法类似,我创建了这个扩展方法,DataRow它需要填充一个参数对象。主要区别在于除了填充对象的属性之外,它还填充给定对象的字段。这也适用于更简单的结构(虽然我只在对象上进行了测试)。

public static T ToObject<T>( this DataRow dataRow )
     where T : new() {
    T item = new T();
    foreach( DataColumn column in dataRow.Table.Columns ) {
        if( dataRow[column] != DBNull.Value ) {
            PropertyInfo prop = item.GetType().GetProperty( column.ColumnName );
            if( prop != null ) {
                object result = Convert.ChangeType( dataRow[column], prop.PropertyType );
                prop.SetValue( item, result, null );
                continue;
            }
            else {
                FieldInfo fld = item.GetType().GetField( column.ColumnName );
                if( fld != null ) {
                    object result = Convert.ChangeType( dataRow[column], fld.FieldType );
                    fld.SetValue( item, result );
                }
            }
        }
    }
    return item;
}

You can put this code in your current class or in a global static class. It needs following namespaces...

您可以将此代码放在当前类或全局静态类中。它需要以下命名空间...

using System;
using System.Data;
using System.Reflection;

Usage is as simple as...

用法很简单...

MyClassName obj = dataRow.ToObject<MyClassName>()

回答by Nashe

Here is an extension method that would allow you to convert a DataRowto a given object.

这是一个扩展方法,允许您将 a 转换为DataRow给定的对象。

public static class DataRowExtensions
{
    public static T Cast<T>(this DataRow dataRow) where T : new()
    {
        T item = new T();

        IEnumerable<PropertyInfo> properties = item.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
                                                             .Where(x => x.CanWrite);

        foreach (DataColumn column in dataRow.Table.Columns)
        {
            if (dataRow[column] == DBNull.Value)
            {
                continue;
            }

            PropertyInfo property = properties.FirstOrDefault(x => column.ColumnName.Equals(x.Name, StringComparison.OrdinalIgnoreCase));

            if (property == null)
            {
                continue;
            }

            try
            {
                Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;

                object safeValue = (dataRow[column] == null) ? null : Convert.ChangeType(dataRow[column], t);

                property.SetValue(item, safeValue, null);
            }
            catch
            {
                throw new Exception($"The value '{dataRow[column]}' cannot be mapped to the property '{property.Name}'!");
            }

        }

        return item;
    }
}

And you can use the above extension method like so

你可以像这样使用上面的扩展方法

foreach (DataRow row in dataTable.Rows)
{
    SomeClassType obj = row.Cast<SomeClassType>();
    // do something with your object
}