patterncsharpMinor
Looping through columns in Entity Framework
Viewed 0 times
loopingcolumnsthroughframeworkentity
Problem
Is there a cleaner/more efficient way to loop through the columns in EF implicitly than the way written below?
I've tried simply doing a
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
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[] CreateAccessors(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(p)
})
.ToArray();
return propertyAccessors.Select(p => p.Accessor).ToArray();
}
static Func CreatePropertyAccessor(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>(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
Solution
So I had a look and made a few modifications, see below with comments.
Usage is a little different now, you would call it like this:
To be extra-super cool (ie. generic) you could even pass in an
Usage
// Made the method generic, the constaint is required by DbSet
static void LoopThroughColumns(Func> getTable)
where T : class
{
using (var db = new someDbContext())
{
// Selecting columns exlicitly was unnecessary
var query = getTable(db);
var columnAccessors = CreateAccessors();
foreach (var row in query)
{
foreach (var col in columnAccessors)
{
var val = col(row);
}
}
}
}
// Parameter is unnecessary as you never used it
static Func[] CreateAccessors()
{
// Index and Property values weren't being used
// ToArray() was an unnecessary conversion
var propertyAccessors = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.CanRead)
.Select((p, i) => CreatePropertyAccessor(p));
return propertyAccessors.Select(e => e).ToArray();
}
static Func CreatePropertyAccessor(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>(castAsObject, param);
return lambda.Compile();
}Usage is a little different now, you would call it like this:
LoopThroughColumns(e => e.someTable);To be extra-super cool (ie. generic) you could even pass in an
Action and have that define what is done with val, then derive different methods on that one. Below I'm creating a PrintColumnValues method which calls LoopThroughColumns with an specific Action to perform.static void LoopThroughColumns(Func> getTable, Action actionOnObject)
where T : class
{
using (var db = new someDbContext())
{
var query = getTable(db);
var columnAccessors = CreateAccessors();
foreach (var row in query)
{
foreach (var col in columnAccessors)
{
actionOnObject(col(row));
}
}
}
}
static void PrintColumnValues(Func> getTable)
where T : class
{
LoopThroughColumns(getTable,
new Action(e =>
{
Console.WriteLine(e);
}));
}Usage
PrintColumnValues(e => e.someTable);Code Snippets
// Made the method generic, the constaint is required by DbSet
static void LoopThroughColumns<T>(Func<someDbContext, DbSet<T>> getTable)
where T : class
{
using (var db = new someDbContext())
{
// Selecting columns exlicitly was unnecessary
var query = getTable(db);
var columnAccessors = CreateAccessors<T>();
foreach (var row in query)
{
foreach (var col in columnAccessors)
{
var val = col(row);
}
}
}
}
// Parameter is unnecessary as you never used it
static Func<T, object>[] CreateAccessors<T>()
{
// Index and Property values weren't being used
// ToArray() was an unnecessary conversion
var propertyAccessors = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.CanRead)
.Select((p, i) => CreatePropertyAccessor<T>(p));
return propertyAccessors.Select(e => e).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();
}LoopThroughColumns(e => e.someTable);static void LoopThroughColumns<T>(Func<someDbContext, DbSet<T>> getTable, Action<object> actionOnObject)
where T : class
{
using (var db = new someDbContext())
{
var query = getTable(db);
var columnAccessors = CreateAccessors<T>();
foreach (var row in query)
{
foreach (var col in columnAccessors)
{
actionOnObject(col(row));
}
}
}
}
static void PrintColumnValues<T>(Func<someDbContext, DbSet<T>> getTable)
where T : class
{
LoopThroughColumns(getTable,
new Action<object>(e =>
{
Console.WriteLine(e);
}));
}PrintColumnValues(e => e.someTable);Context
StackExchange Code Review Q#21634, answer score: 3
Revisions (0)
No revisions yet.