Some of my entities have IEnabledEntity interface.
I want to check in repository if entity implements interface then add some predicate. I have the following code:
public class Repository<T> : IRepository<T> where T : class, IEntity, new()
{
public IQueryable<T> Get(Expression<Func<T, bool>> predicate, params string[] includes)
IQueryable<T> query = Context.Set<T>();
foreach (var include in includes)
{
query = query.Include(include);
}
query = query.Where(predicate);
var isEnabledEntity = typeof(IEnabledEntity).IsAssignableFrom(typeof(T));
if (isEnabledEntity)
{
query = query.Where(e => ((IEnabledEntity) e).IsEnabled);
}
return query;
}
public interface IEnabledEntity
{
bool IsEnabled { get; set; }
}
public class Test : IBaseEntity, IEnabledEntity
{
// ...
public bool IsEnabled { get; set; }
}
But, I get exception about casting:
Unable to cast the type 'Domain.Test' to type 'Domain.Interfaces.IEnabledEntity'. LINQ to Entities only supports casting EDM primitive or enumeration types.
How to make it work?
Linq-to-Entities only knows models which are classes, that's why an expression can't contain an interface type. However clearly it's possible runtime to access the IsEnabled property if T implements it, so if you do the check yourself with IsAssignableFrom() (like you do), it's possible to use the ExpressionVisitor class to bypass the casting:
internal class IgnoreCast : ExpressionVisitor
{
protected override Expression VisitUnary(UnaryExpression e)
{
if(e.NodeType == ExpressionType.Convert && e.Type.IsAssignableFrom(typeof(e.Operand))
return e.Operand;
else
return e;
}
}
Then you need to create your filter with an extensionmethod which implements the IgnoreCast class:
internal static class LocalExtensions
{
internal static IgnoreCast ic = new IgnoreCast();
internal static IQueryable<T> FilterEnabled<T>(this IQueryable<T> query) where T: class
{
Expression<Func<T,bool>> expr = e => ((IEnabledEntity)e).IsEnabled;
expr = (Expression<Func<T,bool>>)ic.Visit(e);
return query.Where(expr);
}
}
Then you can just use that method in your program:
if(typeof(IEnabledEntity).IsAssignableFrom(T))
query = query.FilterEnabled();
The base method Visit(Expression e) will pass each node of the expression to a more specialized Visit method for that kind of node. The Convert nodetype is a UnaryExpression so this method will be overriden in the derived class. If the unaryexpression is of the Convert nodetype and the operand implements the type it will just return the operand, thus removing the casting.
The type parameter in IQueryable<T> is covariant, so instead of worrying about casting the entity in your expression, just safe-cast the entire query itself and then use Cast<T>() to get it back to your entity type:
public IQueryable<T> Get(Expression<Func<T, bool>> predicate, params string[] includes)
{
IQueryable<T> query = Context.Set<T>();
foreach (var include in includes)
{
query = query.Include(include);
}
query = query.Where(predicate);
var enabledQuery = query as IQueryable<IEnabledEntity>;
if (enabledQuery != null)
query = enabledQuery.Where(e => e.IsEnabled).Cast<T>();
return query;
}
Related
Editing this question in the hope to make it clearer.
We have entity framework code first setup. I've simplified two classes for the purposes of example, in reality there are around 10+ more classes similar to the 'Record', where Item is a navigational property/foreign key.
Item class:
public class Item
{
public int Id { get; set; }
public int AccountId { get; set; }
public List<UserItemMapping> UserItemMappings { get; set; }
public List<GroupItemMapping> GroupItemMappings { get; set; }
}
Record class:
public class Record
{
public int ItemId { get; set; }
public Item Item { get; set; }
}
this.User is an injected user object into each repo and is contained on the repository base.
We have an Item repository with the following code:
var items = this.GetAll()
.Where(i => i.AccountId == this.User.AccountId);
I created the follow expression on the repository base to easily filter on that (in the hope of re-use). We cannot use static extension methods due to how LINQ to entities works (System.NotSupportedException "LINQ to Entities does not recognize the method X and this method cannot be translated into a store expression.").
protected Expression<Func<Item, bool>> ItemIsOnAccount()
{
return item => item.AccountId == this.User.AccountId;
}
I have solved the case of the above, by doing this:
var items = this.GetAll().Where(this.ItemIsOnAccount());
We have additional filtering based on user permissions within that account (again, another case where I do not want to repeat this code in every repo we have):
protected Expression<Func<Item, bool>> SubUserCanAccessItem()
{
return item => this.User.AllowAllItems
|| item.UserItemMappings.Any(d => d.UserId.Value == this.User.Id)
|| item.GroupItemMappings.Any(vm =>
vm.Group.GroupUserMappings
.Any(um => um.UserId == this.User.Id));
}
Which I am able to use as follows:
var items = this.GetAll().Where(this.SubUserCanAccessItem());
However, what we also need, in the Record repository is a way to solve the following:
var records = this.GetAll()
.Where(i => i.Item.AccountId == this.User.AccountId);
Because Item is a single navigational property, I do not know how to apply the expressions I have created to this object.
I want to reuse the expression I created in the repo base on all of these other repos, so that my 'permission based' code is all in the same place, but I cannot simply throw it in because the Where clause in this case is of Expression< Func < Record,bool >>.
Creating an interface with a method of:
Item GetItem();
on it and putting it on the Record class does not work because of LINQ to entities.
I cannot also create a base abstract class and inherit from it, because there could be other objects than Item that need to be filtered on. For instance a Record could also have a 'Thing' on it that has permission logic. Not all objects will require to be filtered by 'Item' and 'Thing', some by only one, some by another, some by both:
var items = this.GetAll()
.Where(this.ItemIsOnAccount())
.Where(this.ThingIsOnAccount());
var itemType2s = this.GetAll().Where(this.ThingIsOnAccount());
var itemType3s = this.GetAll().Where(this.ItemIsOnAccount());
Due to this having a single parent class would not work.
Is there a way in which I can reuse the expressions I have already created, or at least create an expression/modify the originals to work across the board within the OTHER repos that of course return their own objects in a GetAll, but all have a navigation property to Item? How would I need to modify the other repos to work with these?
Thanks
The first step for expression reusability is to move the expressions to a common static class. Since in your case they are tied to User, I would make them User extension methods (but note that they will return expressions):
public static partial class UserFilters
{
public static Expression<Func<Item, bool>> OwnsItem(this User user)
=> item => item.AccountId == user.AccountId;
public static Expression<Func<Item, bool>> CanAccessItem(this User user)
{
if (user.AllowAllItems) return item => true;
return item => item.UserItemMappings.Any(d => d.UserId.Value == user.Id) ||
item.GroupItemMappings.Any(vm => vm.Group.GroupUserMappings.Any(um => um.UserId == user.Id));
}
}
Now the Item repository would use
var items = this.GetAll().Where(this.User.OwnsItem());
or
var items = this.GetAll().Where(this.User.CanAccessItem());
In order to be reusable for entities having Item reference, you would need a small helper utility for composing lambda expressions from other lambda expressions, similar to Convert Linq expression "obj => obj.Prop" into "parent => parent.obj.Prop".
It's possible to implement it with Expression.Invoke, but since not all query providers support for invocation expressions (EF6 doesn't for sure, EF Core does), as usual we'll use a custom expression visitor for replacing a lambda parameter expression with another arbitrary expression:
public static partial class ExpressionUtils
{
public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
=> new ParameterReplacer { Source = source, Target = target }.Visit(expression);
class ParameterReplacer : ExpressionVisitor
{
public ParameterExpression Source;
public Expression Target;
protected override Expression VisitParameter(ParameterExpression node)
=> node == Source ? Target : node;
}
}
And the two composing functions are as follows (I don't like the name Compose, so sometimes I use the name Map, sometimes Select, Bind, Transform etc., but functionally they do the same. In this case I'm using Apply and ApplyTo, with the only difference being the transformation direction):
public static partial class ExpressionUtils
{
public static Expression<Func<TOuter, TResult>> Apply<TOuter, TInner, TResult>(this Expression<Func<TOuter, TInner>> outer, Expression<Func<TInner, TResult>> inner)
=> Expression.Lambda<Func<TOuter, TResult>>(inner.Body.ReplaceParameter(inner.Parameters[0], outer.Body), outer.Parameters);
public static Expression<Func<TOuter, TResult>> ApplyTo<TOuter, TInner, TResult>(this Expression<Func<TInner, TResult>> inner, Expression<Func<TOuter, TInner>> outer)
=> outer.Apply(inner);
}
(Nothing special there, code provided for completeness)
Now you could reuse the original filters by "applying" them to a expression which selects Item property from another entity:
public static partial class UserFilters
{
public static Expression<Func<T, bool>> Owns<T>(this User user, Expression<Func<T, Item>> item)
=> user.OwnsItem().ApplyTo(item);
public static Expression<Func<T, bool>> CanAccess<T>(this User user, Expression<Func<T, Item>> item)
=> user.CanAccessItem().ApplyTo(item);
}
and add the following to the entity repository (in this case, Record repository):
static Expression<Func<Record, Item>> RecordItem => entity => entity.Item;
which would allow you to use there
var records = this.GetAll().Where(this.User.Owns(RecordItem));
or
var records = this.GetAll().Where(this.User.CanAccess(RecordItem));
This should be enough to satisfy your requirements.
You can go further and define an interface like this
public interface IHasItem
{
Item Item { get; set; }
}
and let the entities implement it
public class Record : IHasItem // <--
{
// Same as in the example - IHasItem.Item is auto implemented
// ...
}
then add additional helpers like this
public static partial class UserFilters
{
public static Expression<Func<T, Item>> GetItem<T>() where T : class, IHasItem
=> entity => entity.Item;
public static Expression<Func<T, bool>> OwnsItem<T>(this User user) where T : class, IHasItem
=> user.Owns(GetItem<T>());
public static Expression<Func<T, bool>> CanAccessItem<T>(this User user) where T : class, IHasItem
=> user.CanAccess(GetItem<T>());
}
which would allow you omit the RecordItem expression in the repository and use this instead
var records = this.GetAll().Where(this.User.OwnsItem<Record>());
or
var records = this.GetAll().Where(this.User.CanAccessItem<Record>());
Not sure if it gives you a better readability, but is an option, and syntactically is closer to Item methods.
For Thing etc. just add similar UserFilters methods.
As a bonus, you can go even further and add the usual PredicateBuilder methods And and Or
public static partial class ExpressionUtils
{
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
=> Expression.Lambda<Func<T, bool>>(Expression.AndAlso(left.Body,
right.Body.ReplaceParameter(right.Parameters[0], left.Parameters[0])), left.Parameters);
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
=> Expression.Lambda<Func<T, bool>>(Expression.OrElse(left.Body,
right.Body.ReplaceParameter(right.Parameters[0], left.Parameters[0])), left.Parameters);
}
so you could use something like this if needed
var items = this.GetAll().Where(this.User.OwnsItem().Or(this.User.CanAccessItem()));
in the Item repository, or
var records = this.GetAll().Where(this.User.OwnsItem<Record>().Or(this.User.CanAccessItem<Record>()));
in the Record repository.
I can't really tell if this could work in your case, depends on how your entities might be setup, but one thing you can try is to have an interface like IHasItemProperty with a GetItem() method and have the entities where you want to use this implement that interface. Something like this :
public interface IHasItemProperty {
Item GetItem();
}
public class Item: IHasItemProperty {
public Item GetItem() {
return this;
}
public int UserId {get; set;}
}
public class Record: IHasItemProperty {
public Item item{get;set;}
public Item GetItem() {
return this.item;
}
}
public class Repo
{
protected Expression<Func<T, bool>> ItemIsOnAccount<T>() where T: IHasItemProperty
{
return entity => entity.GetItem().UserId == 5;
}
}
I have used an int just to make things simpler.
You should be able to do this with .AsQueryable().
class Account
{
public IEnumerable<User> Users { get; set; }
public User SingleUser { get; set; }
static void Query()
{
IQueryable<Account> accounts = new Account[0].AsQueryable();
Expression<Func<User, bool>> userExpression = x => x.Selected;
Expression<Func<Account, bool>> accountAndUsersExpression =
x => x.Users.AsQueryable().Where(userExpression).Any();
var resultWithUsers = accounts.Where(accountAndUsersExpression);
Expression<Func<Account, bool>> accountAndSingleUserExpression =
x => new[] { x.SingleUser }.AsQueryable().Where(userExpression).Any();
var resultWithSingleUser = accounts.Where(accountAndSingleUserExpression);
}
}
class User
{
public bool Selected { get; set; }
}
You should only use sql (or your database like) items for the predicate. If you put this.User.AccountId into your lambda, that does not exists at database and can't be parsed by it, that's the source of your error message.
I am writing a system that has something similar to roles; a user can only see data that they have rights to. This applies to data used for form population, searches, lists, reports, etc.
The way I planned on implementing this adding a filter to Get requests by adding a "WHERE" clause to the EF query just before execution.
This would be simple were it not for the fact that we are using generics.
The Get function used to be this
public class EntityFactory<TEntity, TDto> : IEntityFactory<TEntity, TDto> where TEntity : class
{
private readonly DBContext _context;
private readonly IMapper _mapper;
private DbSet<TEntity> _dbset;
public EntityFactory(DBContext context, IMapper mapper)
{
//...
}
public async Task<List<TDto>> GetAsync()
{
List<TEntity> d = await _dbset.AsNoTracking().ToListAsync();
return _mapper.Map<List<TDto>>(d);
}
}
And what I would like to do:
public async Task<List<TDto>> GetAsync()
{
//If the object implements a special interface
if (i.GetInterfaces().Contains(typeof(IFoo)))
{
//expression to filter the data on a linked table containing the user's Id.
Expression<Func<Bar, bool>> exp = x => x.Foos.Any(a => a.UserId == _user.UserId);
//add the expression to the dbSet
_dbSet = _dbSet.Where(exp);
}
//Execute the get
List<TEntity> d = await q.AsNoTracking().ToListAsync();
//return the converted objects
return _mapper.Map<List<TDto>>(d);
}
But this does not work! I get this compiler error:
Argument 2: cannot convert from 'System.Linq.Expressions.Expression<System.Func<Bar, bool>>' to 'System.Linq.Expressions.Expression<System.Func<TEntity, int, bool>>'
Is there a way to either:
create a "dynamic" query that is not checked or
change the dbset to the required type, apply the expression and return it to the generic type?
You could use Linq dynamic query to apply where clause.
var query = _dbSet.AsQueryable();
//If the object implements a special interface
if (typeof(IFoo).IsAssignableFrom(typeof(TEntity)))
{
query = query.Where("UserId = #0", _userId);
}
List<TEntity> d = await query.AsNoTracking().ToListAsync();
You may be better served by finding a different way of looking at this problem. Since this is a security filter, you could find that unexpectedly a IFoo wasn't implemented and you aren't filtering when you thought you were.
That being said, you can do this but it requires a couple of steps. You could build the expression manually, but I prefer to build the expression in code and then use a ReplaceVisitor to modify the expression for the current type.
First I create a filtering expression of type Expression<Func<IFoo,bool>>. This isn't the final filtering expression but it is compatible since we are checking to see that the generic type implements IFoo.
Next I use an Expression Visitor to replace each reference to the IFoo parameter expression with a TEntity parameter expression. The resulting expression will be an Expresssion<Func<TEntity,bool>>, so I cast it to that so the compiler will be happy.
Finally, I pass the resulting expression to the Where clause.
Note: This is a non-async version, but it demonstrates the principles.
public class EntityFactory<TEntity, TDto> : IEntityFactory<TEntity, TDto> where TEntity : class
{
private readonly DbContext _context;
private readonly IMapper _mapper = new Mapper(new MapperConfiguration(v => { }));
private DbSet<TEntity> _dbSet;
private Type i = typeof(TEntity);
private Expression<Func<IFoo, bool>> getFilterExpression(int userId)
{
return (x => x.Foos.Any(a => a.UserId == userId));
}
private class ReplaceVisitor : ExpressionVisitor
{
readonly Expression _originalExpression;
readonly Expression _replacementExpression;
public ReplaceVisitor(Expression originalExpression, Expression replacementExpression)
{
_originalExpression = originalExpression;
_replacementExpression = replacementExpression;
}
public override Expression Visit(Expression node)
{
return _originalExpression == node ? _replacementExpression : base.Visit(node);
}
public static Expression VisitExpression(Expression node, Expression originalExpression, Expression replacementExpression)
{
return new ReplaceVisitor(originalExpression, replacementExpression).Visit(node);
}
}
public List<TDto> Get()
{
IQueryable<TEntity> query = _dbSet;
//If the object implements a special interface
if (i.GetInterfaces().Contains(typeof(IFoo)))
{
var userId = 7;
var baseFilterExpression = getFilterExpression(userId);
var filterExpression = (Expression<Func<TEntity, bool>>)ReplaceVisitor.VisitExpression(
baseFilterExpression,
baseFilterExpression.Parameters.First(),
Expression.Parameter(typeof(TEntity)));
//add the expression to the dbSet
query = query.Where(filterExpression);
}
List<TEntity> d = query.AsNoTracking().ToList();
return _mapper.Map<List<TDto>>(d);
}
}
public interface IEntityFactory<TEntity, TDTO> { }
public interface IFoo
{
List<FooItem> Foos { get; set; }
}
public class FooItem
{
public int UserId { get; set; }
}
Here I have a generic Repository class I copied from a tutorial page, but specifically my problem is on the two last functions. On my project I have several catalog entities that inherit from CRUDProperties class and there is a property "Activo" in all of them, what I currently want to do is that if the entity inherits from CRUDProperties class I get all the entities with Activo property on true, and if they do not inherit from that class it just gets all entities. But the compiler throws an error stating T is already defined. What should I do?
public class Repository<T> where T : class
{
private readonly projectEntities context;
private IDbSet<T> entities;
string errorMessage = string.Empty;
public Repository(projectEntities context)
{
this.context = context;
}
public T GetById(object id)
{
return context.Set<T>().Find(id);
}
// This is the function that throws me a compilation error
public virtual IList<T> GetAll<T>() where T : CRUDProperties
{
return context.Set<T>().Where(c => c.Activo).ToList();
}
public virtual IList<T> GetAll()
{
return context.Set<T>().ToList();
}
}
The compiler complains about the ambiguous naming of the type parameters. The class already has a type parameter named T, so in the context of the class that type parameter name is already "taken".
But you should be able to accomplish what you want to do simply by renaming the type parameter for the method to something else than T, so your changed method could look like this:
public virtual IList<TCrud> GetAll<TCrud>() where TCrud : CRUDProperties
{
return context.Set<TCrud>().Where(c => c.Activo).ToList();
}
Note: I assume here that CRUDProperties is a class... If it is an interface then you'll also need to copy the class constraint to the method (i.e. change it to where TCrud : class, CRUDProperties)
using this method you can pass custom where clause to to your GetAll Method
public virtual IList<T> GetAll<T>(Expression<Func<T, bool>> predicate)
{
return context.Set<T>().Where(predicate).ToList();
}
In this method we first check if the T type have Activo property, If find this property so we create a custom expression tree and replace with default predicate that returns all records, this function only returns records that have true value in activo property.
public virtual IList<T> GetAll<T>()
{
Expression<Func<T, bool>> predicate = t => true;
if(typeof(T).GetProperty("Activo") != null)
{
var epx = Expression.Parameter(typeof(T), "x");
Expression left = Expression.PropertyOrField(epx, "Activo");
Expression right = Expression.Constant(true);
Expression e1 = Expression.Equal(left, right);
predicate = Expression.Lambda<Func<T, bool>>(e1, new ParameterExpression[] { epx });
}
return context.Set<T>().Where(predicate);
}
I'm trying to build a generic method that EF4.1 to look in both the Database and the Local memory for a particular row in a table that matches a particular criteria.
So far, this is what I have this.
This is the caller.
dbEntities.MyTables.LocalAndDb(delegate(MyTable s)
{ return s.Description.Contains("test"); });
This is LocalAndDb
public static object LocalAndDb<T>(this DbSet<T> myTable, Func<T, bool> function) where T : class
{
// look in local
var item = myTable.Local.Where(o => function((T)o)).FirstOrDefault()
// if not exist, look in the database
if (item == null)
{
Expression<Func<T, bool>> predicate = (u) => function(u);
item = myTable.Where(predicate).FirstOrDefault();
}
return item;
}
The problem is with this line.
item = myTable.Where(predicate).FirstOrDefault();
When it calls the database, it throws this error.
"The LINQ expression node type 'Invoke' is not supported in LINQ to Entities."
I imagine it's because I'm passing in an anonymous method and it doesn't know how to turn this into SQL. I thought converting it to an Expression object would do the trick but it's still not working for me.
What do I need to do to make a anonymous method become something that LINQ can turn into SQL?
To make this work, you need to pass the lambda expression to LocalAndDb as an expression tree (so that LINQ to Entities can analyze the code and translate it to SQL):
public static object LocalAndDb<T>(this DbSet<T> myTable,
Expression<Func<T, bool>> expr) where T : class {
// ...
if (item == null) {
item = myTable.Where(expr).FirstOrDefault();
}
return item;
}
Then, of course, the problem is that you cannot execute the expression tree when checking the in-memory data. One way to solve this is to use the Compile method of Expression<T>, but that will be a bit inefficient (depending on your scenario).
Another option is to just pass the condition as both function and expression tree:
public static object LocalAndDb<T>(this DbSet<T> myTable,
Func<T, boo> function, Expression<Func<T, bool>> expr) where T : class {
var item = myTable.Local.Where(o => function((T)o)).FirstOrDefault();
if (item == null) {
item = myTable.Where(expr).FirstOrDefault();
}
return item;
}
table.LocalAndDb(t => t.Foo > 10, t => t.Foo > 10);
This is a bit ugly, but it doesn't require inefficient compilation at runtime. If you want a slightly more sophisticated solution, then you can define your own type to keep pre-compiled functions:
class Precompiled<T1, T2> {
public Precompiled(Expression<Func<T1, T2>> expr) {
this.Expression = expr;
this.Function = expr.Compile();
}
public Expression<Func<T1,T2>> Expression { get; private set; }
public Func<T1,T2> Function { get; private set; }
}
I'm trying to build a generic class to work with entities from EF. This class talks to repositories, but it's this class that creates the expressions sent to the repositories. Anyway, I'm just trying to implement one virtual method that will act as a base for common querying. Specifically, it will accept a an int and it only needs to perform a query over the primary key of the entity in question.
I've been screwing around with it and I've built a reflection which may or may not work. I say that because I get a NotSupportedException with a message of LINQ to Entities does not recognize the method 'System.Object GetValue(System.Object, System.Object[])' method, and this method cannot be translated into a store expression. So then I tried another approach and it produced the same exception but with the error of The LINQ expression node type 'ArrayIndex' is not supported in LINQ to Entities. I know it's because EF will not parse the expression the way L2S will.
Anyway, I'm hopping someone with a bit more experience can point me into the right direction on this. I'm posting the entire class with both attempts I've made.
public class Provider<T> where T : class {
protected readonly Repository<T> Repository = null;
private readonly string TEntityName = typeof(T).Name;
[Inject]
public Provider(
Repository<T> Repository) {
this.Repository = Repository;
}
public virtual void Add(
T TEntity) {
this.Repository.Insert(TEntity);
}
public virtual T Get(
int PrimaryKey) {
// The LINQ expression node type 'ArrayIndex' is not supported in
// LINQ to Entities.
return this.Repository.Select(
t =>
(((int)(t as EntityObject).EntityKey.EntityKeyValues[0].Value) == PrimaryKey)).Single();
// LINQ to Entities does not recognize the method
// 'System.Object GetValue(System.Object, System.Object[])' method,
// and this method cannot be translated into a store expression.
return this.Repository.Select(
t =>
(((int)t.GetType().GetProperties().Single(
p =>
(p.Name == (this.TEntityName + "Id"))).GetValue(t, null)) == PrimaryKey)).Single();
}
public virtual IList<T> GetAll() {
return this.Repository.Select().ToList();
}
protected virtual void Save() {
this.Repository.Update();
}
}
UPDATE for #Gabe
This is what my repository class looks like:
public class Repository<T> where T : class {
protected readonly ObjectContext ObjectContext = null;
private readonly IObjectSet<T> ObjectSet = null;
[Inject]
public Repository(
ObjectContext ObjectContext) {
this.ObjectContext = ObjectContext;
this.ObjectSet = this.ObjectContext.CreateObjectSet<T>();
}
public virtual void Delete(
T Entity) {
this.ObjectSet.DeleteObject(Entity);
}
public virtual void Insert(
T Entity) {
this.ObjectSet.AddObject(Entity);
}
public virtual IQueryable<T> Select() {
return this.ObjectSet;
}
public virtual IQueryable<T> Select(
Expression<Func<T, bool>> Selector) {
return this.ObjectSet.Where(Selector);
}
public virtual void Update() {
this.ObjectContext.SaveChanges();
}
}
The names of the methods are based on the SQL functions, not on the LINQ methods, which is where I think you're getting confused on how my repository functions.
As Pauli alludes to, you need to manually create Expression trees, although reflection isn't necessary in this case. Here's how you could write your Get function:
public virtual T Get(
int PrimaryKey)
{
var param = Expression.Parameter(typeof(T));
// create expression for param => param.TEntityNameId == PrimaryKey
var lambda = Expression.Lambda<Func<T, bool>>(
Expression.Equal(
Expression.Property(param, TEntityName + "Id"),
Expression.Constant(PrimaryKey)),
param);
return this.Repository.Single(lambda);
}
Also, note that your GetAll function doesn't need Select -- return Repository.ToList(); will work just as well.