Reputation: 51094
I'm using some code from a book to implement a generic repository class for EF data access. the code uses the following two methods to get a single entity by its int id
primary key, assuming all DB objects have an int PK. However, I am using an imported DB with mainly natural keys, and I wish to preserve all the FK relationships as they are, i.e. I don't want to redesign the DB to use single column int PK's.
How can I adapt the code below to work with multi-column keys?
protected Expression<Func<T, bool>> CreateGetExpression<T>(int id)
{
ParameterExpression e = Expression.Parameter(typeof(T), "e");
PropertyInfo propInfo = typeof(T).GetProperty(KeyPropertyName);
MemberExpression m = Expression.MakeMemberAccess(e, propInfo);
ConstantExpression c = Expression.Constant(id, typeof(int));
BinaryExpression b = Expression.Equal(m, c);
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(b, e);
return lambda;
}
public override T Get<T>(int id)
{
return List<T>().FirstOrDefault(CreateGetExpression<T>(id));
}
I want my Get
method to look like this:
public override T Get<T>(params object[] keyValues)
{
return List<T>().FirstOrDefault(CreateGetExpression<T>(keyValues));
}
Upvotes: 1
Views: 887
Reputation: 1503280
Well, you basically need to build up an expression tree with multiple equality checks. You can take the code you've got for building a single equality check, and build up multiple ones, one for each key. Then you need to combine them using Expression.AndAlso
multiple times - so if you've got individual equality checks e1
, e2
and e3
you might use:
var e = Expression.AndAlso(Expression.AndAlso(e1, e2), e3);
One thing to note: you'll need to use a single ParameterExpression
for the whole final expression - so you'll need to adapt your "build a single check" method to take a ParameterExpression
as a parameter... and you don't need to use Expression.Lambda
until the very end. So the overall steps will be something like:
ParameterExpression
BinaryExpression
using Expression.Equals
, using the same ParameterExpression
you've just created.Expression.AndAlso
Expression.Lambda
at the very end to create an Expression<Func<T, bool>>
Upvotes: 1