Linq2SQL - selecting items using reflection
I'm trying to load a collection of entities using Linq2SQL. The problem is, I dont know what the entities are,IList<object>
. I have tried to select them using reflection, but I get an out of memory error when I do the select, I presume because the context is unable to parse my expression,and is loading everything from the DB.
If anyone has any advice on this, or an alternative way to do what I want, please let me know.
foreach (object entity in requiredEntities)
{
Type entityType = entity.GetType();
IQueryable<object> entityTable = (IQueryable<object>)dataContext.GetTable(entityType);
// grab the objects primary key field
var pkeyField = entityType.GetProperties(开发者_StackOverflow).SingleOrDefault(p =>
p.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute),true)
.Cast<System.Data.Linq.Mapping.ColumnAttribute>()
.Any(attrib => attrib.IsPrimaryKey));
object pkeyValue = pkeyField.GetValue(entity,null);
Func<object,bool> primaryKeySelector = o => pkeyField.GetValue(o,null) == pkeyValue;
// crash here, out of memory exception
object result = entityTable.Where(primaryKeySelector).SingleOrDefault();
}
By using a delegate you are forcing it to use LINQ-to-Objects, which is why it is running out of memory. What you need to do is build an Expression
instead. Equally, it is bad practice to use the attributes as that is not the only model that LINQ-to-SQL supports; it is preferable to look at dataContext.Mapping.GetMetaType(entityType)
to get the primary key.
If you have 4.0, the following should work:
var entityType = typeof(User);
var metaType = dataContext.Mapping.GetMetaType(entityType);
var member = metaType.DataMembers.Single(m => m.IsPrimaryKey).Member;
var param = Expression.Parameter(entityType);
var body = Expression.Equal(Expression.MakeMemberAccess(param, member),
Expression.MakeMemberAccess(Expression.Constant(entity), member));
dynamic table = dataContext.GetTable(entityType);
object result = Cheeky(table, body, param);
with
static T Cheeky<T>(ITable<T> source, Expression body, ParameterExpression param)
where T : class
{
var predicate = Expression.Lambda<Func<T, bool>>(body, param);
return source.SingleOrDefault(predicate);
}
精彩评论