简体   繁体   中英

Datatable to object by using reflection and linq

I have a datatable like this

Name| Value
----|------
NA  |  VA
NB  |  VB
NC  |  VC1
NC  |  VC2
ND  |  VD1
ND  |  VD2

and a class like this

Class NVMapping {
  List<string> NC { get; set; }
  List<string> ND { get; set; }
  string NA { get; set; }
  string NB { get; set; }
}

How to use linq or other way to transfer the datatable to this type ?

I think I need to emphasize one thing here. This kinda mapping will be a lot in my application.

Somehow I think using reflection can make this function be generic to handle all these kinda mapping.

So if possible, I would prefer a generic function like using reflection to achieve this.

If possible, it will even better just transfering datatable into an object like above transformation.

Thanks !

May I suggest writing a generic method that uses reflection. The following method uses reflection to populate a class's public properties from a DataRow in a DataTable (or a List<> of classes, one from each DataRow in the DataTable) where the ColumnName matches the name of the public property in the class exactly (case-sensitive). If the DataTable has extra columns that don't match up to a property in the class, they are ignored. If the DataTable is missing columns to match a class property, that property is ignored and left at the default value for that type (since it is a property).

public static IList<T> DatatableToClass<T>(DataTable Table) where T : class, new()
    {
        if (!Helper.IsValidDatatable(Table))
            return new List<T>();

        Type classType = typeof(T);
        IList<PropertyInfo> propertyList = classType.GetProperties();

        // Parameter class has no public properties.
        if (propertyList.Count == 0)
            return new List<T>();

        List<string> columnNames = Table.Columns.Cast<DataColumn>().Select(column => column.ColumnName).ToList();

        List<T> result = new List<T>();
        try
        {
            foreach (DataRow row in Table.Rows)
            {
                T classObject = new T();
                foreach (PropertyInfo property in propertyList)
                {
                    if (property != null && property.CanWrite)   // Make sure property isn't read only
                    {
                        if (columnNames.Contains(property.Name))  // If property is a column name
                        {
                            if (row[property.Name] != System.DBNull.Value)   // Don't copy over DBNull
                            {
                                object propertyValue = System.Convert.ChangeType(
                                        row[property.Name],
                                        property.PropertyType
                                    );
                                property.SetValue(classObject, propertyValue, null);
                            }
                        }
                    }
                }
                result.Add(classObject);
            }
            return result;
        }
        catch
        {
            return new List<T>();
        }
    }

If you interested in going the other way, and fill out a DataTable from a class's public properties, I cover that and more on my C# blog, CSharpProgramming.tips/Class-to-DataTable

Here it is:

IEnumerable<DataRow> rows = table.AsEnumerable();
string naValue = null;
var naRow = rows.FirstOrDefault(r => r.Field<string>("Name") == "NA");
if(naRow != null)
    naValue = naRow.Field<string>("Value");
string nbValue = null;
var nbRow = rows.FirstOrDefault(r => r.Field<string>("Name") == "NB");
if(nbRow != null)
    nbValue = nbRow.Field<string>("Value");
NVMapping map = new NVMapping {
    NC = rows.Where(r => r.Field<string>("Name") == "NC")
        .Select(r => r.Field<string>("Value")).ToList(),
    ND = rows.Where(r => r.Field<string>("Name") == "ND")
        .Select(r => r.Field<string>("Value")).ToList(),
    NA = naValue,
    NB = nbValue
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM