我有一个表示列表中项目的类。我在其函数中调用返回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;
}
}
我做得对吗? 我怎样才能改善这个?
答案 0 :(得分:25)
如果你只是在它可能会好的时候使用它,但如果你会做很多,你应该尝试做一些更通用的东西。我写了一篇关于如何为DataTable
编写扩展方法的博客文章,该方法创建了一个对象列表。按照约定,对象中的属性应该与存储过程中的列具有相同的名称(如果可以的话,我会更改存储过程中的名称):
public static class DataTableExtensions
{
public static IList<T> ToList<T>(this DataTable table) where T : new()
{
IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
IList<T> result = new List<T>();
foreach (var row in table.Rows)
{
var item = CreateItemFromRow<T>((DataRow)row, properties);
result.Add(item);
}
return result;
}
public static IList<T> ToList<T>(this DataTable table, Dictionary<string, string> mappings) where T : new()
{
IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
IList<T> result = new List<T>();
foreach (var row in table.Rows)
{
var item = CreateItemFromRow<T>((DataRow)row, properties, mappings);
result.Add(item);
}
return result;
}
private static T CreateItemFromRow<T>(DataRow row, IList<PropertyInfo> 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<T>(DataRow row, IList<PropertyInfo> properties, Dictionary<string, string> 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<Item>();
或
var mappings = new Dictionary<string,string>();
mappings.Add("ItemId", "item_id");
mappings.Add("ItemName ", "item_name");
mappings.Add("Price ", "price);
var items = dt.ToList<Item>(mappings);
博客文章位于:http://blog.tomasjansson.com/2010/11/convert-datatable-to-generic-list-extension
有许多方法可以扩展它,你可以包含某种映射字典,告诉扩展如何映射列,这样名称就不需要匹配了。或者,您可以添加要在映射中排除的属性名称列表。
更新:您正在创建的对象(Item
)必须具有默认构造函数,否则私有方法将无法创建它。由于解决方案的工作方式首先是创建对象,而不是使用从反射中获取的属性来设置对象的值。
更新2:我添加了带有映射字典的部分,但我自己没有尝试过,所以可能无法编译。但是,这个概念已存在,我认为它有效。
答案 1 :(得分:5)
非常好,但我有一些建议:
不要将ToString转换成东西 解析回另一种类型。这个 可能会导致数据损坏 类型,并且速度慢/效率低。
期待并检查来自SQL Server的null。
所以,而不是:
ItemId = long.Parse(row[_ItemIdDataName].ToString());
尝试:
ItemId = row.Field<long?>(_ItemIdDataName) ?? value_if_null;
(添加对System.Data.DatasetExtensions的引用以获取Field扩展名)
答案 2 :(得分:2)
答案 3 :(得分:0)
您的私人物品构造函数和load()
函数在Item
类中似乎属于。
你知道,一堂课应该做好一件事。
所以试着去
1.将私有c'tor重构为一个帮助类,只需解析DataRow并返回一个Item实例
2.将load()
重构为一个不同的类,它只使用上面的辅助方法并返回一个Item对象实例数组