Does this code lend itself to a generalized routine? - c#

Here is code I just wrote in the context of Linq2Sql:
public static CampaignEntity GetOrCreate(int pid, SynchDBDataContext db)
{
CampaignEntity ce = (from c in db.CampaignEntities
where c.pid == pid
select c).FirstOrDefault();
if (ce == null)
{
ce = new CampaignEntity();
ce.pid = pid;
db.CampaignEntities.InsertOnSubmit(ce);
}
return ce;
}
The things to make a generic routine would be:
- the entity type
- the type of the primary key column
- the value of the primary key

What I've seen done before is something like this:
public static TEntity GetOrCreate<TEntity, TPKey>(TPKey pid, SyncDBCataContext db, Func<int, TEntity> create){...}
The Func would be the method that creates the entity, so you could inline it when you call this function or you could take this out and hard-code how an entity is created like you have done in your question.
Here is a method that will get by id:
public T GetById<TEntity, TPKey>(TPKey id, DataContext context) where TEntity : class
{
MetaTable metaTable = context.Mapping.GetTable(typeof(TEntity));
MetaDataMember primaryKeyMetaDataMember = metaTable.RowType.DataMembers.SingleOrDefault(d => d.IsPrimaryKey);
return context.GetTable<TEntity>().SingleOrDefault(GetEqualityLambdaExpression<TEntity>(primaryKeyMetaDataMember.Name, id));
}
Here is a method that will create the expression for the filter needed by the get by id method:
public Expression<Func<T, bool>> GetEqualityLambdaExpression<T>(string fieldName, object constantValue)
{
ParameterExpression param = Expression.Parameter(typeof(T), "e");
Expression<Func<T, bool>> expression = Expression.Lambda<Func<T, bool>>(
Expression.Equal(Expression.Property(param, fieldName),
Expression.Constant(constantValue)),
new ParameterExpression[] { param });
return expression;
}
As you can see there is some use of reflection. If performance is a big concern, you can implement some sort of caching to reduce the overhead in future calls.

Related

Map Expression<Func<Dto, bool>> to Expression<Func<Entity, bool>> using AutoMapper

I have a repository->service architecture that uses a LINQ expression to filter many data. Repositories work with entities and Services with the DTOs. At the moment, I use Automapper to map entity to dto and vice-versa. In the repository, I have a method that accepts an Expression> LINQ expression. This method is called by the service using an Expression> LINQ expression. So, I've used Automapper to map the service's expression to the repository's expression.
The project builds successfully but I have an error at runtime.
This is the method that throws the error in the service:
public IQueryable<TDto> GetBy(Expression<Func<TDto, bool>> predicate)
=> this.Repository.GetBy(Mapper.Map<Expression<Func<TEntity, bool>>>(predicate))
.ProjectTo<TDto>(Mapper.ConfigurationProvider);
And this is the method called in the repository:
public IQueryable<TEntity> GetBy(Expression<Func<TEntity, bool>> predicate)
=> this.Context.Set<TEntity>().AsNoTracking().Where(predicate);
The mapping between entity and dto is the following:
CreateMap<TEntity, TDto>();
CreateMap<TDto, TEntity>();
At runtime I'm receiving this error:
AutoMapper.AutoMapperMappingException: 'Missing type map configuration or unsupported mapping.'
Also, i've tryed to map explicitly the expressions:
CreateMap<Expression<Func<TEntity, bool>>, Expression<Func<TDto, bool>> >();
CreateMap<Expression<Func<TDto, bool>>, Expression<Func<TEntity, bool>>>();
But i've received this error:
System.InvalidOperationException: 'Code supposed to be unreachable'
Does anyone have a possible solution?
I have never seen capability to automaticaly transform lambdas.
What you should do instead is to try use Project method.
For example:
var predicate = new Func<Dto, bool>(d => d.Id == 2);
var query = mapper.ProjectTo<Dto>(entities, null).Where(predicate);
Query will be equivalent of:
var query = entities
.Select(e => new Dto { Id = e.Id, [...] }) // mapping created using map registered in AutoMapper
.Where(d => d.Id == 2)
Another thing you can do is to map expression by yourself. As a starpoint you can use query produced by Project method:
var query = mapper.ProjectTo<Dto>(entities, null);
var lambda = (LambdaExpression)((UnaryExpression)((MethodCallExpression) query.Expression).Arguments[1]).Operand;
var body = (MemberInitExpression)lambda.Body;
var bindings = body.Bindings;
As a result of the code above you will have array of bindings like dto.Id = entity.Id.
Having that it should be pretty easy to write custom mapper:
public static class MapperExtensions
{
public static Expression<Func<TEntity, bool>> ConvertPredicate<TDto, TEntity>(this Mapper mapper, Expression<Func<TDto, bool>> predicate)
{
return (Expression<Func<TEntity, bool>>)new PredicateVisitor<TDto, TEntity>(mapper).Visit(predicate);
}
public class PredicateVisitor<TDto, TEntity> : ExpressionVisitor
{
private readonly ParameterExpression _entityParameter;
private readonly MemberAssignment[] _bindings;
public PredicateVisitor(Mapper mapper)
{
IQueryable<TDto> mockQuery = mapper.ProjectTo<TDto>(new TEntity[0].AsQueryable(), null);
LambdaExpression lambdaExpression = (LambdaExpression)((UnaryExpression)((MethodCallExpression) mockQuery.Expression).Arguments[1]).Operand;
this._bindings = ((MemberInitExpression)lambdaExpression.Body).Bindings.Cast<MemberAssignment>().ToArray();
this._entityParameter = Expression.Parameter(typeof(TEntity));
}
// This is required to modify type parameters
protected override Expression VisitLambda<T>(Expression<T> node)
{
return Expression.Lambda(
base.Visit(node.Body),
node.Parameters.Select(p => (ParameterExpression)base.Visit(p)).ToArray()
);
}
// Do member mapping
protected override Expression VisitMember(MemberExpression node)
{
MemberInfo member = node.Member;
MemberAssignment binding = this._bindings.FirstOrDefault(b => b.Member == member);
if (binding != null)
{
return base.Visit(binding.Expression);
}
return base.VisitMember(node);
}
// Replace parameters reference
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == typeof(TDto))
{
return this._entityParameter;
}
if (node.Type == typeof(TEntity))
{
return this._entityParameter;
}
return base.VisitParameter(node);
}
}
}

linq lambda expression for sql contains

I am using a generic repository, like this:
itemsList = (from myrow in UoW.FileRepository.Get()
select new FileModel()
{record_id = myrow.type_id,
descr = myrow.descr}).ToList();});
And this is the Get method:
public virtual IEnumerable<TEntity> Get()
{
// _aQuery = _theDbContext.Set<TEntity>();
IEnumerable<TEntity> query = _aQuery;
return query;
}
How would I implement a generic linq lambda expression if I wanted to create a similar query to search for a particular string in a particular field? In my viewmodel I would like to call something like:
from myrow in UoW.FileRepository.Srch(nameofFieldToSearch, searchString).
The query would look something like this?
public IEnumerable<TEntity> Srch(Expression<Func<TEntity, bool>> expression)
{
IEnumerable<TEntity> srchList = _aQuery.ToList();
return srchList.Where(????);
}
Thank you for your suggestions.
EDIT-----------------------
I have all my queries like Get and Srch in a general repository class and for now just need to know how to declare the query in the repository class and how to call it with the search string from my viewmodel. I am not sure if there is a consensus as to where/when to materialize and compile? I saw another discussion http://www.fascinatedwithsoftware.com/blog/post/2012/01/10/More-on-Expression-vs-Func-with-Entity-Framework.aspx and I quote from it below to inquire whether that is the same approach being suggested here? Thank you again.
"The profiler told us that LoadMyEntities was being called many, many times and it was taking a large fraction of our CPU time. The simple change below solved the problem. Can you guess why?"
public IEnumerable<MyEntity> LoadMyEntities(Func<MyEntity, bool> predicate)
{return Context.MyEntities.Where(predicate);}
"The parameter is now a Func<> instead of an Expression>. The reason this makes a difference is that a predicate that's in the form of an Expression is passed to SQL server, but a predicate that's passed as a Func is not. Normally, you'd want SQL Server to do as much for you as possible, and an Expression would be the right choice, but in this case we'd like to pre-load the entire table in the context -- which is exactly what a Func will do.
The Where extension method has two flavors. One extends IQueryable and takes an Expression parameter. The other extends IEnumerable and takes a Func.
Because 'predicate' is now a Func, the Where that extends IEnumerable is used.
The Entity Framework's fluent interface for constructing SQL queries is based on IQueryables, not IEnumerables. Therefore, the fluency stops just before the Where. The part of the statement that gets passed to the Entity Framework is just Context.MyEntities.
Context.MyEntities therefore returns the entire table to the context.
The entire table is now filtered with the predicate, and the value we really want is returned.
The next time the method is called, the Entity Framework realizes that the record we want is already in the context. (In my case, we were querying by the primary key, and EF is apparently smart enough to know that if there's a record in the context with that ID, it won't find an additional such record in the database.) Since we don't go out to SQL Server, we save lots of time. Obviously there are occasions when you would not want this, but in our case it was exactly what we wanted. The table was relatively small, and the same context was queried hundreds of times.
In the original version, the predicate was an Expression, so the compiler used the Where that extends IQueryable. The predicate was thus passed to SQL Server, which dutifully returned just one row to the context. The next time we called LoadMyEntities, Entity Framework had to call SQL Server again."
Please take a look at msdn repository pattern
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
This will provide more complete Generic Get method.
For search you could Try
public IEnumerable<TEntity> GlobalSearch(Expression<Func<TEntity, bool>> expression)
{
return Get(expression);
}
In DataProvider you could try something like this
Note This is not may be exact implementation, but will give you basic idea, how to invoke.
public List<Users> Search(List<string> userList)
{
Expression<Func<User, bool>> expression = x=>UserList.Contains(x.UserName);
return GlobalSearch(expression);
}
Example of Repository pattern
This would be a simple implementation using the Expression trees. Following is the complete solution:
Method to fetch the Expression for Srch method:
Public Expression<Func<TEntity, bool>> SrchExpression(string nameofFieldToSearch, string searchString)
{
var parameterType = Expression.Parameter(typeof(TEntity), "obj");
var memberExpression = Expression.Property(typeof(string), nameofFieldToSearch)
// Calls Extension method created underneath
var filtersMethodInfo = typeof(StringExtensions).GetMethod("Contains", new[] { typeof(string), typeof(string) });
var filtersConstantExpression = Expression.Constant(searchString, typeof(string));
var finalExpression = Expression.Call(null, filtersMethodInfo, memberExpression, filtersConstantExpression)
return Expression.Lambda<Func<TEntity, bool>>(finalExpression, parameterType)
}
// Create a String extension method for Contains
public static class StringExtensions
{
public static bool Contains(this string source, string searchString)
{
return source?.IndexOf(subString, StringComparison.OrdinalIgnoreCase) >= 0;
}
}
Now your Srch method shall look like:
public IEnumerable<TEntity> Srch(Expression<Func<TEntity, bool>> expression)
{
Func<TEntity, bool>> func = expression.Compile();
IEnumerable<TEntity> srchList = _aQuery.Where(o => func(o));
return srchList;
}

Guid identifier - make PK or add as additional property?

I want to add a Guid identifier to a few of my entities.
My initial approach was to make it the Primary Key for those entities. But that seems to make the rest of my code more complex.
For example we must now allow for multiple ID types in the generic repository and specify the PK type for each DbEntity (code samples below).
Therefore I am considering maintaining a consistent int PK on all entities, and adding the Guid as an additional property when required. This also means that I don't have to worry about ensuring the Guid is not used as a clustering key.
Simpler code. No cluster worries. The 'additional property' approach looks like a winner to me.
However I don't see it mentioned, used or recommended anywhere. (In comparison there are plenty of articles disussing using a Guid for a PK).
Are there any disadvantages to this approach? Could doing things this way come back and bite me?
Using Only Int as PK
public class DbEntity
{
[Key]
public int ID { get; set; }
}
public class Car : DbEntity
{}
public class House: DbEntity
{}
public virtual T SelectByID(int id, params Expression<Func<T, object>>[] includeExpressions)
{
var set = includeExpressions.Aggregate<Expression<Func<T, object>>, IQueryable<T>>
(table, (current, expression) => current.Include(expression));
return set.SingleOrDefault(i => i.ID == id);
}
public virtual T SelectByGuid(string guid, params Expression<Func<T, object>>[] includeExpressions)
{
var set = includeExpressions.Aggregate<Expression<Func<T, object>>, IQueryable<T>>
(table, (current, expression) => current.Include(expression));
return set.SingleOrDefault(i => i.AdditionalGuidProperty == guid);
}
Using Both Int and Guid as PK
public class DbEntity<PKT>
{
[Key]
public PKT ID { get; set; }
}
public class Car : DbEntity<int>
{}
public class House : DbEntity<guid>
{}
public virtual T SelectByID(PKT id, params Expression<Func<T, object>>[] includeExpressions)
{
var set = includeExpressions.Aggregate<Expression<Func<T, object>>, IQueryable<T>>
(table, (current, expression) => current.Include(expression));
ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
PropertyInfo propertyInfo = typeof(T).GetProperty("ID");
MemberExpression memberExpression = Expression.MakeMemberAccess(parameter, propertyInfo);
ConstantExpression constantExpression = Expression.Constant(id, typeof(PKT));
BinaryExpression binaryExpression = Expression.Equal(memberExpression, constantExpression);
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(binaryExpression, parameter);
return set.SingleOrDefault(lambda);
}

Convert Expression<Func<T,T,bool>> to Expression<Func<T,bool>>

I have an expression like this
(a,b) => a.Id == b.Id
I would like to use it in LINQ to Entities query
T GetSingle(IRepository<T> repository, Func<T,T,bool> predicate, T entity)
{
return repository.GetAll().Single(e => predicate(e, entity))
}
but this results the exception: LINQ expression node type 'Invoke' is not supported in LINQ to Entities
As I understand I can use Expressions to construct a valide predicate for LINQ2SQL, so my expression
(a,b) => a.Id == b.Id and instance of entity with Id = 5 can result a new expression (a) => a.Id == 5.
And the last expression will be fine for LINQ to Entities.
I found and read this articles
Replace parameter in lambda expression
http://www.codeproject.com/Articles/143096/Parameter-Substitution-within-Expression-Trees
but still has no clue how to solve my task
So, how do I convert given expression dynamically?
Why don't you just change your method to be:
T GetSingle(IRepository<T> repository, Expression<Func<TSource, Boolean>> predicate)
{
return repository.GetAll().Single(predicate);
}
so instead of this:
GetSingle(myRepository, (a,b) => a.Id == b.Id, myEntity);
you should be able to do this:
GetSingle(myRepository, a => a.Id == myEntity.Id);
I haven't tested it with Linq2SQL, but it seems to me that you should be able to do this with an expression visitor and compiling the expression to write the value of your parameter into the expression you've supplied (assuming you switch over to using Expression<Func<T, T, bool>> instead of Func<T, T, bool>) and creating a wrapper that itself invokes Enumerable.Single on the result from the GetAll
The visitor (for specifically the example you've given would look like this)
public class VariableSubstitutionVisitor : ExpressionVisitor
{
private readonly ParameterExpression _parameter;
private readonly ConstantExpression _constant;
public VariableSubstitutionVisitor(ParameterExpression parameter, ConstantExpression constant)
{
_parameter = parameter;
_constant = constant;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node == _parameter)
{
return _constant;
}
return node;
}
}
Now, we'd adjust the GetSingle method to look like this:
public T GetSingle(IRepository<T> repository, Expression<Func<T, T, bool>> predicate, T entity)
{
//Create a new representation of predicate that will take just one parameter and capture entity
//Get just the body of the supplied expression
var body = predicate.Body;
//Make a new visitor to replace the second parameter with the supplied value
var substitutionVisitor = new VariableSubstitutionVisitor(predicate.Parameters[1], Expression.Constant(entity, typeof(T)));
//Create an expression that represents the predicate with the second parameter replaced with the supplied entity
var visitedBody = substitutionVisitor.Visit(body).Reduce();
//Make the new expression into something that could be a Func<T, bool>
var newBody = Expression.Lambda<Func<T, bool>>(visitedBody, predicate.Parameters[0]);
//Now, create something that will call Enumerable.Single on the result of GetAll from the repository, supplying the new predicate
//Make a place to hold the result of GetAll
var resultsParameter = Expression.Parameter(typeof (IEnumerable<T>));
//Make an expression that calls the Single extension method
var singleExpression = Expression.Call(((Func<IEnumerable<T>, Func<T, bool>, T>)Enumerable.Single).Method, resultsParameter, newBody);
//Make a Func<IEnumerable<T>, T> that return the result of the call of Single on the results of the GetAll method
var compiled = Expression.Lambda<Func<IEnumerable<T>, T>>(singleExpression, resultsParameter).Compile();
//Call GetAll, letting the new method that we've got run the supplied predicate without having to run an Invoke type expression
return compiled(repository.GetAll());
}
The trick, of course, is getting that to perform well.

How do I make an anonymous method run in LINQ to Entities?

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; }
}

Categories

Resources