Speed Neo
Speed Neo

Reputation: 57

Expressions as parameter

I'm using a expression as parameter for inserting data (with EF) :

public bool Exists(Expression<Func<V, bool>> predicate)
{
    return _dbContext.Set<V>().Any(predicate);
}

public void AddIfNotExists(V entity, Expression<Func<V, bool>> predicate)
{
    if (!Exists(predicate))
        Add(entity);
}

I have a method nammed Synchronize with a different expression :

protected void Synchronize<T>(string resource, Expression<Func<T, T, bool>> predicate) where T : class
{
    var list = _context.RestClient.Get<List<T>>(resource);

    using (var repo = new Repository<XContext, T>())
    {
        list.ForEach(x =>
        {
            repo.AddIfNotExists(x, y => predicate.Compile().Invoke(x, y));
        });

        repo.Save();
    }
}

I need two parameters for my method Synchronize :

Synchronize<ClientLivraison>("clientlivraison", (x, y) => x.IdClientJuridique == y.IdClientJuridique && x.IdClientLivraison == y.IdClientLivraison);

At runtime, I have this exception :

System.NotSupportedException : 'LINQ to Entities does not recognize the method 'Boolean Invoke(X.X.SynchroDb.Entity.Origine, X.X.SynchroDb.Entity.Origine)' method, and this method cannot be translated into a store expression.'

My question, how convert/pass my expression

Expression<Func<T, T, bool>>

To

Expression<Func<T, bool>>

Upvotes: 1

Views: 221

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205539

It is possible to convert Expression<Func<T, T, bool>> to Expression<Func<T, bool>> by replacing the first or second parameter using custom ExpressionVisitor and Expression.Lambda method.

But the easier and more natural way would be to change the Synchronize method argument

Expression<Func<T, T, bool>> predicate

to

Func<T, Expression<Func<T, bool>>> predicateFactory>

i.e. a function delegate with parameter T, which when invoked returns Expression<Func<T, bool>> based on the passed argument.

From the caller perspective, it would be a matter of changing

(x, y) => x.IdClientJuridique == y.IdClientJuridique && x.IdClientLivraison == y.IdClientLivraison

to

x => y => x.IdClientJuridique == y.IdClientJuridique && x.IdClientLivraison == y.IdClientLivraison

and the implementation would be simply replacing

repo.AddIfNotExists(x, y => predicate.Compile().Invoke(x, y));

with

repo.AddIfNotExists(x, predicateFactory(x));

Here is the whole method:

protected void Synchronize<T>(string resource, Func<T, Expression<Func<T, bool>>> predicateFactory) where T : class
{
    var list = _context.RestClient.Get<List<T>>(resource);

    using (var repo = new Repository<GmaoContext, T>())
    {
        list.ForEach(x =>
        {
            repo.AddIfNotExists(x, predicateFactory(x));
        });

        repo.Save();
    }
}

Upvotes: 2

Related Questions