using System; using System.Reflection; using System.Data.SqlClient; using System.Linq; using System.Linq.Expressions; using System.Collections.Generic; namespace xxxxxxxxxxxx { public class ListHelper<T> { public List<T> CreateList(SqlDataReader reader) { Func<SqlDataReader, T> readRow = this.GetReader(reader); var results = new List<T>(); while (reader.Read()) results.Add(readRow(reader)); return results; } public List<T> SortList(List<T> listToSort, string propertyName, bool ascending) { // verify that the propertyName is valid var propertyNames = typeof(T).GetProperties().ToList().Select(p => p.Name).ToList(); if (!propertyNames.Contains(propertyName)) throw new ArgumentOutOfRangeException("There is no property named: " + propertyName); var paramExpression = Expression.Parameter(typeof(T), "item"); var propertyExpression = Expression.Convert(Expression.Property(paramExpression, propertyName), typeof(object)); var lambdaExpression = Expression.Lambda<Func<T, object>>(propertyExpression, paramExpression); if (ascending) return listToSort.AsQueryable().OrderBy(lambdaExpression).ToList(); else return listToSort.AsQueryable().OrderByDescending(lambdaExpression).ToList(); } private Func<SqlDataReader, T> GetReader(SqlDataReader reader) { Delegate resDelegate; List<string> readerColumns = new List<string>(); for (int index = 0; index < reader.FieldCount; index++) readerColumns.Add(reader.GetName(index)); // a list of LINQ expressions that will be used for each data row var statements = new List<Expression>(); // get the indexer property of SqlDataReader var indexerProperty = typeof(SqlDataReader).GetProperty("Item", new[] { typeof(string) }); // Parameter expression to create instance of object ParameterExpression instanceParam = Expression.Variable(typeof(T)); ParameterExpression readerParam = Expression.Parameter(typeof(SqlDataReader)); // create and assign new instance of variable BinaryExpression createInstance = Expression.Assign(instanceParam, Expression.New(typeof(T))); statements.Add(createInstance); // loop through each of the properties in T to determine how to populate the new instance properties var properties = typeof(T).GetProperties(); var columnNames = this.GetColumnNames(properties); foreach (var property in properties) { string columnName = columnNames[property.Name]; //string columnName = property.Name; if (readerColumns.Contains(columnName)) { // get the instance.Property MemberExpression setProperty = Expression.Property(instanceParam, property); // the database column name will be what is in the columnNames list -- defaults to the property name IndexExpression readValue = Expression.MakeIndex(readerParam, indexerProperty, new[] { Expression.Constant(columnName) }); ConstantExpression nullValue = Expression.Constant(DBNull.Value, typeof(System.DBNull)); BinaryExpression valueNotNull = Expression.NotEqual(readValue, nullValue); if (property.PropertyType.Name.ToLower().Equals("string")) { ConditionalExpression assignProperty = Expression.IfThenElse( valueNotNull, Expression.Assign(setProperty, Expression.Convert(readValue, property.PropertyType)), Expression.Assign(setProperty, Expression.Constant("", typeof(System.String))) ); statements.Add(assignProperty); } else { ConditionalExpression assignProperty = Expression.IfThen( valueNotNull, Expression.Assign(setProperty, Expression.Convert(readValue, property.PropertyType)) ); statements.Add(assignProperty); } } } var returnStatement = instanceParam; statements.Add(returnStatement); var body = Expression.Block(instanceParam.Type, new[] { instanceParam }, statements.ToArray()); var lambda = Expression.Lambda<Func<SqlDataReader, T>>(body, readerParam); resDelegate = lambda.Compile(); return (Func<SqlDataReader, T>)resDelegate; } private Dictionary<string, string> GetColumnNames(PropertyInfo[] properties) { var columnNames = new Dictionary<string, string>(); foreach (var property in properties) { string columnName = property.Name; var attributes = property.GetCustomAttributes(typeof(Attributes.DatabaseProperty), true); if (attributes.Length > 0) columnName = ((Attributes.DatabaseProperty)attributes[0]).ColumnName; columnNames.Add(property.Name, columnName); } return columnNames; } } }
[AttributeUsage(AttributeTargets.Property)] public class DatabaseProperty : Attribute { private string _columnName; public string ColumnName { get { return _columnName; } set { _columnName = value; } } }
[Serializable] public class Employee { public int EmployeeID { get; set; } public string LastName { get; set; } public string FirstName { get; set; } public string Title { get; set; } public DateTime? BirthDate { get; set; } public DateTime? HireDate { get; set; } public string City { get; set; } public string Notes { get; set; } public byte[] Photo { get; set; } } [Serializable] public class Customer { public int CustomerID { get; set; } [DatabaseProperty(ColumnName = "CompanyName")] public string Name { get; set; } public string ContactName { get; set; } public string ContactTitle { get; set; } public string Address { get; set; } public string City { get; set; } public string Region { get; set; } public string PostalCode { get; set; } public string Country { get; set; } public string Phone { get; set; } public string Fax { get; set; } }
使用demo:
using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["northwind"].ConnectionString)) { conn.Open(); var query = "select * from Employees order by LastName, FirstName"; var cmd = new SqlCommand(query, conn); using (var reader = cmd.ExecuteReader()) { this.EmployeeList = new GenericPopulator.ListHelper<Models.Employee>().CreateList(reader); this.EmployeeList = new GenericPopulator.ListHelper<Models.Employee>().SortList(this.EmployeeList, "LastName", true); rptEmployees.DataSource = this.EmployeeList; rptEmployees.DataBind(); gvEmployees.DataSource = this.EmployeeList; gvEmployees.DataBind(); reader.Close(); } conn.Close(); }