Shi*_*hin 6 c# types datagridview list
我有一些表示数据库表的类,要加载每个表的行DataGridView,我有一个List<>函数,在循环中获取该表中的所有行.
public List<class_Table1> list_rows_table1()
{
// class_Table1 contains each column of table as public property
List<class_Table1> myList = new List<class_Table1>();
// sp_List_Rows: stored procedure that lists data
// from Table1 with some conditions or filters
Connection cnx = new Connection;
Command cmd = new Command(sp_List_Rows, cnx);
cnx.Open;
IDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
class_Table1 ct = new class_Table1();
ct.ID = Convert.ToInt32(dr[ID_table1]);
ct.Name = dr[name_table1].ToString();
//... all others wanted columns follow here
myList.Add(ct);
}
dr.Close();
cnx.Close();
// myList contains all wanted rows; from a Form fills a dataGridView
return myList();
}
Run Code Online (Sandbox Code Playgroud)
而对于其他表,其他一些功能:list_rows_table2,list_rows_table3 ...我的问题是:如何创建一个唯一的List<>功能,在那里我可以动态指定类型List<>返回,或者如何转换,例如List<object>到List<myClass>返回之前.
您可以拥有一个所有数据类必须实现的接口
public interface IData
{
void FillFromReader(IDataReader dr);
}
Run Code Online (Sandbox Code Playgroud)
然后像这样改变你的方法
public List<T> GetList<T>(string sqlText)
where T : IData, new()
{
List<T> myList = new List<T>();
using (Connection cnx = new Connection(connString))
using (Command cmd = new Command(sqlText, cnx)) {
cnx.Open();
using (IDataReader dr = cmd.ExecuteReader()) {
while (dr.Read())
{
T item = new T();
item.FillFromReader(dr);
myList.Add(item);
}
}
}
return myList();
}
Run Code Online (Sandbox Code Playgroud)
所以基本上每个班级都要负责填写自己的领域.
where T : IData, new()泛型类型参数的约束是至关重要的.它告诉方法,T必须实现接口IData.这对于能够在FillFromReader不进行强制转换的情况下调用方法是必要的.数据类必须具有默认构造函数(由此指定new().这使您可以实例化一个new T().
我使用连接,命令和带有using语句的数据读取器包围了代码.该using语句在块结束时自动关闭并释放资源,并确保发生这种情况,即使应该抛出异常或者语句块应该过早地使用return语句.
奥利维尔的实施很好。它使用泛型和接口,为每个实体提供自己的 FillFromDataReader() 实现。
你可以走得更远。通过使用约定,所有数据水合代码都可以集中并抽象出来。
我假设您的类属性名称和列名称相同。如果不是,则可以扩展以下代码以将别名属性添加到属性名称中。有时,某个属性是根据对象中的其他值计算得出的,该属性无法进行水合。可以在下面的类中创建和实现 Ignore 属性。
public class DataAccess
{
/// <summary>
/// Hydrates the collection of the type passes in.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sql">The SQL.</param>
/// <param name="connection">The connection.</param>
/// <returns>List{``0}.</returns>
public List<T> List<T>(string sql, string connection) where T: new()
{
List<T> items = new List<T>();
using (SqlCommand command = new SqlCommand(sql, new SqlConnection(connection)))
{
string[] columns = GetColumnsNames<T>();
var reader = command.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
T item = new T();
foreach (var column in columns)
{
object val = reader.GetValue(reader.GetOrdinal(column));
SetValue(item, val, column);
}
items.Add(item);
}
command.Connection.Close();
}
return items;
}
/// <summary>
/// Sets the value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="item">The item.</param>
/// <param name="value">The value.</param>
/// <param name="column">The column.</param>
private void SetValue<T>(T item, object value, string column)
{
var property = item.GetType().GetProperty(column);
property.SetValue(item, value, null);
}
/// <summary>
/// Gets the columns names.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns>System.String[][].</returns>
private string[] GetColumnsNames<T>() where T : new()
{
T item = new T();
return (from i in item.GetType().GetProperties()
select i.Name).ToArray();
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码中有一些注意事项。DBNull 和 Nullable 类型是特殊情况,需要自定义代码来处理它们。我通常将 DBNull 转换为 null。我从来没有遇到过需要区分两者之间差异的情况。对于 Nullalbe 类型,只需检测 Nullable 类型并相应地处理代码即可。
ORM 将消除处理数据访问的大部分麻烦。缺点是很多时候您会耦合到 DTO 和数据库模式。当然这个问题可以通过使用抽象来解决。许多公司仍然严格使用存储过程,大多数 ORM 在被迫使用存储过程时就会崩溃。它们只是不适合与存储过程一起使用。
我编写了一个名为“ Hysonic ”的数据访问框架。它位于 GitHub 上,专门设计用于处理存储过程。上面的代码是它的一个轻量级实现。
| 归档时间: |
|
| 查看次数: |
891 次 |
| 最近记录: |