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();
}