كيف يمكنك تحويل DataTable إلى قائمة عامة؟
سؤال
حاليًا، أستخدم:
DataTable dt = CreateDataTableInSomeWay();
List<DataRow> list = new List<DataRow>();
foreach (DataRow dr in dt.Rows)
{
list.Add(dr);
}
هل هناك طريقة أفضل/سحرية؟
المحلول
إذا كنت تستخدم .NET Framework 3.5، يمكنك استخدام <لأ href = "http://msdn.microsoft.com/en-us/library/system.data.datatableextensions.asenumerable.aspx" يختلط = "noreferrer "> DataTableExtensions.AsEnumerable
(وطريقة التمديد) ثم إذا كنت حقا بحاجة الى List<DataRow>
بدلا من IEnumerable<DataRow>
فقط يمكنك الاتصال <لأ href =" http://msdn.microsoft.com/en-us/library/bb342261. ASPX "يختلط =" noreferrer "> Enumerable.ToList
:
IEnumerable<DataRow> sequence = dt.AsEnumerable();
أو
using System.Linq;
...
List<DataRow> list = dt.AsEnumerable().ToList();
نصائح أخرى
List<Employee> emp = new List<Employee>();
//Maintaining DataTable on ViewState
//For Demo only
DataTable dt = ViewState["CurrentEmp"] as DataTable;
//read data from DataTable
//using lamdaexpression
emp = (from DataRow row in dt.Rows
select new Employee
{
_FirstName = row["FirstName"].ToString(),
_LastName = row["Last_Name"].ToString()
}).ToList();
ومع C # 3.0 و System.Data.DataSetExtensions.dll،
List<DataRow> rows = table.Rows.Cast<DataRow>().ToList();
هل يمكن استخدام
List<DataRow> list = new List<DataRow>(dt.Select());
وdt.Select()
سيعود كافة الصفوف في الجدول الخاص بك، ومجموعة من datarows، ومنشئ List
يقبل أن مجموعة من الأشياء كحجة لملء البداية قائمتك معها.
ويمكنك إنشاء وظيفة ملحق على النحو التالي:
public static List<T> ToListof<T>(this DataTable dt)
{
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
var columnNames = dt.Columns.Cast<DataColumn>()
.Select(c => c.ColumnName)
.ToList();
var objectProperties = typeof(T).GetProperties(flags);
var targetList = dt.AsEnumerable().Select(dataRow =>
{
var instanceOfT = Activator.CreateInstance<T>();
foreach (var properties in objectProperties.Where(properties => columnNames.Contains(properties.Name) && dataRow[properties.Name] != DBNull.Value))
{
properties.SetValue(instanceOfT, dataRow[properties.Name], null);
}
return instanceOfT;
}).ToList();
return targetList;
}
var output = yourDataInstance.ToListof<targetModelType>();
إذا كنت ترغب فقط في قائمة القيم من "ID" عاد الحقل عدد صحيح، هل يمكن استخدام ...
List<int> ids = (from row in dt.AsEnumerable() select Convert.ToInt32(row["ID"])).ToList();
using System.Data;
var myEnumerable = myDataTable.AsEnumerable();
List<MyClass> myClassList =
(from item in myEnumerable
select new MyClass{
MyClassProperty1 = item.Field<string>("DataTableColumnName1"),
MyClassProperty2 = item.Field<string>("DataTableColumnName2")
}).ToList();
ولقد أضاف بعض التعديلات على قانون من هذا الجواب ( https://stackoverflow.com/a/24588210/4489664و>) لأن لأنواع nullable فإنه سيعود استثناء
public static List<T> DataTableToList<T>(this DataTable table) where T: new()
{
List<T> list = new List<T>();
var typeProperties = typeof(T).GetProperties().Select(propertyInfo => new
{
PropertyInfo = propertyInfo,
Type = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType
}).ToList();
foreach (var row in table.Rows.Cast<DataRow>())
{
T obj = new T();
foreach (var typeProperty in typeProperties)
{
object value = row[typeProperty.PropertyInfo.Name];
object safeValue = value == null || DBNull.Value.Equals(value)
? null
: Convert.ChangeType(value, typeProperty.Type);
typeProperty.PropertyInfo.SetValue(obj, safeValue, null);
}
list.Add(obj);
}
return list;
}
مرة أخرى، باستخدام 3.5 يمكنك القيام بذلك مثل:
dt.Select().ToList()
برغس
إليك طريقة ملحق DataTable التي تحول DataTable إلى قائمة عامة.
https://Gist.github.com/gaui/a0a615029f1327296cf8
الاستخدام:
List<Employee> emp = dtTable.DataTableToList<Employee>();
وهناك أكثر 'سحر' وسيلة، وليس بحاجة الصافي 3.5.
إذا، على سبيل المثال، DBDatatable
كان عائدا عمود واحد من المعرفات الفريدة العمومية (uniqueidentifier في SQL) ثم هل يمكن استخدام:
Dim gList As New List(Of Guid)
gList.AddRange(DirectCast(DBDataTable.Select(), IEnumerable(Of Guid)))
// this is better suited for expensive object creation/initialization
IEnumerable<Employee> ParseEmployeeTable(DataTable dtEmployees)
{
var employees = new ConcurrentBag<Employee>();
Parallel.ForEach(dtEmployees.AsEnumerable(), (dr) =>
{
employees.Add(new Employee()
{
_FirstName = dr["FirstName"].ToString(),
_LastName = dr["Last_Name"].ToString()
});
});
return employees;
}
وDataTable.Select()
لا يعطي الصفوف بالترتيب الذي كانت موجودة في DataTable.
إذا أمر مهم أشعر بالتكرار خلال جمع datarow وتشكيل قائمة هو الطريق الصحيح للذهاب أو هل يمكن أيضا استخدام الزائد للDataTable.Select(string filterexpression, string sort)
.
ولكن هذا الحمل الزائد قد يتم معالجة كل طلب (مثل أمر من حالة ...) على أن SQL.
DataTable dt; // datatable should contains datacolumns with Id,Name
List<Employee> employeeList=new List<Employee>(); // Employee should contain EmployeeId, EmployeeName as properties
foreach (DataRow dr in dt.Rows)
{
employeeList.Add(new Employee{EmployeeId=dr.Id,EmplooyeeName=dr.Name});
}
استخدم System.Data
مساحة الاسم ثم سوف تحصل .AsEnumerable()
.
/* This is a generic method that will convert any type of DataTable to a List
*
*
* Example : List< Student > studentDetails = new List< Student >();
* studentDetails = ConvertDataTable< Student >(dt);
*
* Warning : In this case the DataTable column's name and class property name
* should be the same otherwise this function will not work properly
*/
<اقتباس فقرة>
وفيما يلي الوظيفتين التي إذا كنا تمرير جدول البيانات ويحددها المستخدم الصف. فإنه سيتم ثم العودة قائمة من تلك الفئة مع البيانات DataTable و.
اقتباس فقرة> public static List<T> ConvertDataTable<T>(DataTable dt)
{
List<T> data = new List<T>();
foreach (DataRow row in dt.Rows)
{
T item = GetItem<T>(row);
data.Add(item);
}
return data;
}
private static T GetItem<T>(DataRow dr)
{
Type temp = typeof(T);
T obj = Activator.CreateInstance<T>();
foreach (DataColumn column in dr.Table.Columns)
{
foreach (PropertyInfo pro in temp.GetProperties())
{
//in case you have a enum/GUID datatype in your model
//We will check field's dataType, and convert the value in it.
if (pro.Name == column.ColumnName){
try
{
var convertedValue = GetValueByDataType(pro.PropertyType, dr[column.ColumnName]);
pro.SetValue(obj, convertedValue, null);
}
catch (Exception e)
{
//ex handle code
throw;
}
//pro.SetValue(obj, dr[column.ColumnName], null);
}
else
continue;
}
}
return obj;
}
<اقتباس فقرة>
وهذه الطريقة سوف تحقق نوع البيانات من الميدان، وتحويل قيمة DataTable وفي لأن نوع البيانات.
اقتباس فقرة> private static object GetValueByDataType(Type propertyType, object o)
{
if (o.ToString() == "null")
{
return null;
}
if (propertyType == (typeof(Guid)) || propertyType == typeof(Guid?))
{
return Guid.Parse(o.ToString());
}
else if (propertyType == typeof(int) || propertyType.IsEnum)
{
return Convert.ToInt32(o);
}
else if (propertyType == typeof(decimal) )
{
return Convert.ToDecimal(o);
}
else if (propertyType == typeof(long))
{
return Convert.ToInt64(o);
}
else if (propertyType == typeof(bool) || propertyType == typeof(bool?))
{
return Convert.ToBoolean(o);
}
else if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?))
{
return Convert.ToDateTime(o);
}
return o.ToString();
}
<اقتباس فقرة>
لاستدعاء الأسلوب السابق، استخدم بناء الجملة التالي:
اقتباس فقرة>List< Student > studentDetails = new List< Student >();
studentDetails = ConvertDataTable< Student >(dt);
<اقتباس فقرة>
وتغيير اسم فئة الطلاب وقيمة DT أساس الاحتياجات الخاصة بك. في هذه الحالة يجب أن يكون اسم والطبقة اسم الخاصية العمود DataTable وفي نفس وإلا هذه الوظيفة لا تعمل بشكل صحيح.
اقتباس فقرة>لقد نجح هذا بالنسبة لي: تحتاج على الأقل إلى .Net Framework 3.5،يعرض الكود الموجود أدناه DataRow الذي تم تحويله إلى Generic.IEnumerable، وقد تم استخدام comboBox1 للحصول على توضيح أفضل.
using System.Linq;
DataTable dt = new DataTable();
dt = myClass.myMethod();
List<object> list = (from row in dt.AsEnumerable() select (row["name"])).ToList();
comboBox1.DataSource = list;
public class ModelUser
{
#region Model
private string _username;
private string _userpassword;
private string _useremail;
private int _userid;
/// <summary>
///
/// </summary>
public int userid
{
set { _userid = value; }
get { return _userid; }
}
/// <summary>
///
/// </summary>
public string username
{
set { _username = value; }
get { return _username; }
}
/// <summary>
///
/// </summary>
public string useremail
{
set { _useremail = value; }
get { return _useremail; }
}
/// <summary>
///
/// </summary>
public string userpassword
{
set { _userpassword = value; }
get { return _userpassword; }
}
#endregion Model
}
public List<ModelUser> DataTableToList(DataTable dt)
{
List<ModelUser> modelList = new List<ModelUser>();
int rowsCount = dt.Rows.Count;
if (rowsCount > 0)
{
ModelUser model;
for (int n = 0; n < rowsCount; n++)
{
model = new ModelUser();
model.userid = (int)dt.Rows[n]["userid"];
model.username = dt.Rows[n]["username"].ToString();
model.useremail = dt.Rows[n]["useremail"].ToString();
model.userpassword = dt.Rows[n]["userpassword"].ToString();
modelList.Add(model);
}
}
return modelList;
}
static DataTable GetTable()
{
// Here we create a DataTable with four columns.
DataTable table = new DataTable();
table.Columns.Add("userid", typeof(int));
table.Columns.Add("username", typeof(string));
table.Columns.Add("useremail", typeof(string));
table.Columns.Add("userpassword", typeof(string));
// Here we add five DataRows.
table.Rows.Add(25, "Jame", "Jame@hotmail.com", DateTime.Now.ToString());
table.Rows.Add(50, "luci", "luci@hotmail.com", DateTime.Now.ToString());
table.Rows.Add(10, "Andrey", "Andrey@hotmail.com", DateTime.Now.ToString());
table.Rows.Add(21, "Michael", "Michael@hotmail.com", DateTime.Now.ToString());
table.Rows.Add(100, "Steven", "Steven@hotmail.com", DateTime.Now.ToString());
return table;
}
protected void Page_Load(object sender, EventArgs e)
{
List<ModelUser> userList = new List<ModelUser>();
DataTable dt = GetTable();
userList = DataTableToList(dt);
gv.DataSource = userList;
gv.DataBind();
}[enter image description here][1]
</asp:GridView>
</div>
ويمكننا استخدام أسلوب عام لتحويل DataTable
إلى List
بدلا من تحويل DataTable
إلى List
يدويا.
ملحوظة: يجب أن يكون DataTable
ColumnName
وType
PropertyName
في نفس
ودعوة أدناه الطريقة:
long result = Utilities.ConvertTo<Student>(dt ,out listStudent);
// Generic Method
public class Utilities
{
public static long ConvertTo<T>(DataTable table, out List<T> entity)
{
long returnCode = -1;
entity = null;
if (table == null)
{
return -1;
}
try
{
entity = ConvertTo<T>(table.Rows);
returnCode = 0;
}
catch (Exception ex)
{
returnCode = 1000;
}
return returnCode;
}
static List<T> ConvertTo<T>(DataRowCollection rows)
{
List<T> list = null;
if (rows != null)
{
list = new List<T>();
foreach (DataRow row in rows)
{
T item = CreateItem<T>(row);
list.Add(item);
}
}
return list;
}
static T CreateItem<T>(DataRow row)
{
string str = string.Empty;
string strObj = string.Empty;
T obj = default(T);
if (row != null)
{
obj = Activator.CreateInstance<T>();
strObj = obj.ToString();
NameValueCollection objDictionary = new NameValueCollection();
foreach (DataColumn column in row.Table.Columns)
{
PropertyInfo prop = obj.GetType().GetProperty(column.ColumnName);
if (prop != null)
{
str = column.ColumnName;
try
{
objDictionary.Add(str, row[str].ToString());
object value = row[column.ColumnName];
Type vType = obj.GetType();
if (value == DBNull.Value)
{
if (vType == typeof(int) || vType == typeof(Int16)
|| vType == typeof(Int32)
|| vType == typeof(Int64)
|| vType == typeof(decimal)
|| vType == typeof(float)
|| vType == typeof(double))
{
value = 0;
}
else if (vType == typeof(bool))
{
value = false;
}
else if (vType == typeof(DateTime))
{
value = DateTime.MaxValue;
}
else
{
value = null;
}
prop.SetValue(obj, value, null);
}
else
{
prop.SetValue(obj, value, null);
}
}
catch(Exception ex)
{
}
}
}
PropertyInfo ActionProp = obj.GetType().GetProperty("ActionTemplateValue");
if (ActionProp != null)
{
object ActionValue = objDictionary;
ActionProp.SetValue(obj, ActionValue, null);
}
}
return obj;
}
}
https://www.nuget.org/packages/AD.GenericConversion/
قم بمراجعة هذه المكتبة للتحويل وستجد كل أنواع التحويل هنا مثل: -
- DataTable إلى GenericList
- نوع عام إلى DataTable
- Json إلى DataTable، قائمة عامة، نوع عام
- DataTable إلى Json
ويمكنك استخدام أسلوب عام من هذا القبيل لDataTable ولقائمة عامة
public static List<T> DataTableToList<T>(this DataTable table) where T : class, new()
{
try
{
List<T> list = new List<T>();
foreach (var row in table.AsEnumerable())
{
T obj = new T();
foreach (var prop in obj.GetType().GetProperties())
{
try
{
PropertyInfo propertyInfo = obj.GetType().GetProperty(prop.Name);
if (propertyInfo.PropertyType.IsEnum)
{
propertyInfo.SetValue(obj, Enum.Parse(propertyInfo.PropertyType, row[prop.Name].ToString()));
}
else
{
propertyInfo.SetValue(obj, Convert.ChangeType(row[prop.Name], propertyInfo.PropertyType), null);
}
}
catch
{
continue;
}
}
list.Add(obj);
}
return list;
}
catch
{
return null;
}
}
وتحويل DataTable
إلى Dictionary
عام
public static Dictionary<object,IList<dynamic>> DataTable2Dictionary(DataTable dt)
{
Dictionary<object, IList<dynamic>> dict = new Dictionary<dynamic, IList<dynamic>>();
foreach(DataColumn column in dt.Columns)
{
IList<dynamic> ts = dt.AsEnumerable()
.Select(r => r.Field<dynamic>(column.ToString()))
.ToList();
dict.Add(column, ts);
}
return dict;
}