Is there a cleaner/more efficient way to loop through the columns in EF implicitly than the way written below?
static void Main(string[] args) {
using (var db = new someDbContext()) {
var query = from p in db.someTable
select new {
column1 = p.column1
column2 = p.column2
};
var columnAccessors = CreateAccessors(query.FirstOrDefault());
foreach (var row in query) {
foreach (var col in columnAccessors) {
var val = col(row);
//Do something with val here.
}
}
}
}
static Func<T, object>[] CreateAccessors<T>(T source = default(T)) {
var propertyAccessors = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.CanRead)
.Select((p, i) => new {
Index = i,
Property = p,
Accessor = CreatePropertyAccessor<T>(p)
})
.ToArray();
return propertyAccessors.Select(p => p.Accessor).ToArray();
}
static Func<T, object> CreatePropertyAccessor<T>(PropertyInfo prop) {
var param = Expression.Parameter(typeof(T), "input");
var propertyAccess = Expression.Property(param, prop.GetGetMethod());
var castAsObject = Expression.TypeAs(propertyAccess, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(castAsObject, param);
return lambda.Compile();
}
I've tried simply doing a foreach (var col in row)
before but I know that it won't work because row doesn't contain a definition for GetEnumerator and I'm not sure how one would go about implementing a solution that would do so generically for something like this.
I was working on implementing a DataReader and came across this page: http://www.developerfusion.com/article/122498/using-sqlbulkcopy-for-high-performance-inserts/. The thought occurred to me that I could modify the CreatePropertyAccessors segments to loop through columns and so I came up with the above. Problem being I'm just not sure that it's a "good" solution.
Edit:
With one small change the following is possible as well:
var query = from p in db.someTable
select new SomeModel {
item1 = p.column1,
item2 = p.column2
};
var columnAccessors = CreateAccessors<SomeModel>();
Console.WriteLine(row.column1 + ", " row.Column2);
Which honestly isn't that bad with only two columns but it starts to get ridiculous once you pass 5 or so. \$\endgroup\$