将datarow提取到c#对象
我有一个类Item表示列表中的项目。 我有函数调用返回datatable的存储过程,我需要将数据表转换为项目数组。 这是我做的:
public class Item { private string _ItemIdDataName = "item_id"; private string _ItemNameDataName = "item_name"; private string _PriceDataName = "price"; public long ItemId { get; set; } public string ItemName { get; set; } public float Price { get; set; } private Item(DataRow row) { if (row != null) { ItemId = long.Parse(row[_ItemIdDataName].ToString()); ItemName = row[_ItemNameDataName].ToString(); Price = float.Parse(row[_PriceDataName].ToString()); } } public Item[] load() { DataTable dt=DBHandler.GetItems();//Stored procedure that returns DataTable Item[] items = new Item[dt.Rows.Count]; for (int i = 0; i < dt.Rows.Count; i++) { items[i] = new Item(dt.Rows[i]); } return items; } }
我做得对吗? 我怎样才能改善这个?
如果你只是在它可能会好的时候使用它,但如果你会做很多,你应该尝试做一些更通用的东西。 我写了一篇关于如何为DataTable
编写扩展方法的博客文章,该方法创建了一个对象列表。 它的惯例是,对象中的属性应该与存储过程中的列具有相同的名称(如果可以的话,我会在存储过程中更改名称):
public static class DataTableExtensions { public static IList ToList (this DataTable table) where T : new() { IList properties = typeof(T).GetProperties().ToList(); IList result = new List (); foreach (var row in table.Rows) { var item = CreateItemFromRow ((DataRow)row, properties); result.Add(item); } return result; } public static IList ToList (this DataTable table, Dictionary mappings) where T : new() { IList properties = typeof(T).GetProperties().ToList(); IList result = new List (); foreach (var row in table.Rows) { var item = CreateItemFromRow ((DataRow)row, properties, mappings); result.Add(item); } return result; } private static T CreateItemFromRow (DataRow row, IList properties) where T : new() { T item = new T(); foreach (var property in properties) { property.SetValue(item, row[property.Name], null); } return item; } private static T CreateItemFromRow(DataRow row, IList properties, Dictionary mappings) where T : new() { T item = new T(); foreach (var property in properties) { if(mappings.ContainsKey(property.Name)) property.SetValue(item, row[mappings[property.Name]], null); } return item; } }
现在你可以打电话了
var items = dt.ToList- ();
要么
var mappings = new Dictionary(); mappings.Add("ItemId", "item_id"); mappings.Add("ItemName ", "item_name"); mappings.Add("Price ", "price); var items = dt.ToList- (mappings);
博客文章在这里: http : //blog.tomasjansson.com/2010/11/convert-datatable-to-generic-list-extension
有许多方法可以扩展它,你可以包含某种映射字典,告诉扩展如何映射列,这样名称就不需要匹配了。 或者,您可以添加要在映射中排除的属性名称列表。
更新:您正在创建的对象( Item
)必须具有默认构造函数,否则私有方法将无法创建它。 由于解决方案的工作方式首先是创建对象,而不是使用从reflection中获取的属性来设置对象的值。
更新2:我添加了带有映射字典的部分,但我自己没有尝试过,所以它可能无法编译。 但是,这个概念是存在的,我认为它有效。
很好,但我有一些建议:
-
不要将ToString转换为要解析回另一种类型的东西。 这可能会导致数据类型损坏,并且速度慢/效率低。
-
期待并检查来自SQL Server的null。
所以,而不是:
ItemId = long.Parse(row[_ItemIdDataName].ToString());
尝试:
ItemId = row.Field(_ItemIdDataName) ?? value_if_null;
(添加对System.Data.DatasetExtensions的引用以获取Field扩展名)
您的私有Item构造函数和load()
函数似乎不属于您的Item
类。
你知道,一堂课应该做好一件事。
所以试着
1.将私有c’tor重构为一个帮助类,只需解析DataRow并返回Item的实例
2.将load()
重构为一个不同的类,它只使用上面的helper方法并返回一个Item对象实例的数组
- 使用entity framework将文件保存在数据库中
- .NET WinForms INotifyPropertyChanged在更改一个绑定时更新所有绑定。 更好的方法?
- 使用数据库中的项填充checkboxlist?
- 使用XmlReader读取属性值
- 更改为通用接口的性能影响
- 具有不变名称“MySql.Data.MySqlClient”的ADO.NET提供程序未在计算机或应用程序配置文件中注册
- 在Window Application中使用HttpContext.Current.Server.MapPath?
- 将对象传递给AutoMapper映射
- MSBuild支持Visual Studio 2017 RTM中的T4模板