Admir Tuzović
Admir Tuzović

Reputation: 11177

Lambda Expression with two IN parameters to Lambda Expression with single IN parameter

I have extension method that has the following signature:

public static class GenericSeeder
{
    public static void Seed<TSeed, TEntity>(this DbContext context, IEnumerable<TSeed> seeds, Expression<Func<TEntity, TSeed, bool>> predicate)
    {
        // code that I'm looking for goes here
    }
}

To have better understanding of what the method is doing, here's how it should be used:

context.Seed<SeedClass, EntityClass>(seeds, (entity, seed) => entity.Name == seed.OtherProperty);

So basically, I am using the predicate to check whether the seed was already applied. However, in order to do a check, I must use Where or FirstOrDefault from Linq to Entities, which takes the following as parameter:

Expression<Func<TEntity, bool>> predicate

So my lambda expression is function of 2 IN parameters (TSeed, TEntity) and 1 OUT parameter (bool). I need to iterate through provided collection of TSeed objects, and for each of those, use that object as parameter for my lambda expression, to generate LINQ 2 Entities lambda expression which has 1 IN parameter (TEntity) and 1 OUT parameter (bool).

Is there a way to do a partial invoke of lambda expression / func to get another lambda expression / func?

Upvotes: 1

Views: 626

Answers (3)

Servy
Servy

Reputation: 203829

Through the use of LINQKit to allow expressions to be invoked in such a way that they will be transformed into other expressions the implementation of your method becomes fairly trivial:

public static IQueryable<TEntity> Seed<TSeed, TEntity>(
    this DbContext context,
    IEnumerable<TSeed> seeds,
    Expression<Func<TEntity, TSeed, bool>> predicate)
{
    return context.Set<TEntity>()
            .AsExpandable()
            .Where(entity => seeds.Any(seed => predicate.Invoke(entity, seed)));
}

Upvotes: 1

Admir Tuzović
Admir Tuzović

Reputation: 11177

I've managed to create solution on my own. I did however use the infamous LinqKit extension library and it's AsExpandable() extension method.

LinqKit can be found here: NuGet link

So this is the implementation that works with Linq 2 Entities:

public static void Seed<TSeed, TEntity>(this DbContext context, IEnumerable<TSeed> seeds, Expression<Func<TEntity, TSeed, bool>> predicate)
            where TEntity : class
            where TSeed : class
        {
            foreach (TSeed seed in seeds)
            {
                Expression<Func<TEntity, bool>> matchExpression = (entity) => predicate.Invoke(entity, seed);
                TEntity existing = context.Set<TEntity>().AsExpandable().FirstOrDefault(matchExpression);

            // Rest of code is omitted as it is not related to the original question.
            // The query above is properly executed by Linq 2 Entities.
            }
        }

Upvotes: 0

AK_
AK_

Reputation: 8099

I have no idea what you are doing, but this is how you do partial application in c#:

Func<int,bool, string> twoInFunc= (int a, bool b) => a.ToString() + b.ToString();

int number = 7;

Func<bool, string> oneInFunc= (bool b) => twoInFunc(number,b);

Upvotes: 0

Related Questions