プロジェクトでDataRowを作成しました。
DataRow datarow;
このDataRowを任意のタイプのオブジェクトに変換したいと思います。どうすればいいですか?
これは私がそれを使用するかなりクールな方法です。
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);
}
class Person{
public string FirstName{get;set;}
public string LastName{get;set;}
}
Person person = new Person();
person.FirstName = dataRow["FirstName"] ;
person.LastName = dataRow["LastName"] ;
または
Person person = new Person();
person.FirstName = dataRow.Field<string>("FirstName");
person.LastName = dataRow.Field<string>("LastName");
アプリケーションの解決策を1つ見つけました。
// 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);
}
}
}
これにより、以下のようにDataRowがViewModelにマップされます。
Your_ViewModel model = CreateItemFromRow<Your_ViewModel>(row);
与えられた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
以前のアプローチのいくつかと同様に、引数オブジェクトを取得する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;
}
このコードは、現在のクラスまたはグローバル静的クラスに配置できます。次の名前空間が必要です...
using System;
using System.Data;
using System.Reflection;
使い方は簡単です...
MyClassName obj = dataRow.ToObject<MyClassName>()
Aviが示す手動の方法とは別に、 AutoMapper のようなマッピングシステムを使用して変換を行うことができます。これは、マップする列/プロパティが多数ある場合に特に役立ちます。
AutoMapperを使用してDataTable
をオブジェクトのリストに変換する方法については この記事 を確認してください。
DataRowには、オブジェクト値の配列を含むプロパティItemArrayがあります。この配列を操作して、DataRowの値を使用して任意のカスタム型を作成できます。
これは、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;
}
}
そして、あなたはそのように上記の拡張方法を使うことができます
foreach (DataRow row in dataTable.Rows)
{
SomeClassType obj = row.Cast<SomeClassType>();
// do something with your object
}