Benjamin Soulier
Benjamin Soulier

Reputation: 2263

Entity Framework - LINQ - Use Expressions in Select

I am using within my code some EF LINQ expressions to keep complex queries over my model in one place:

public static IQueryable<User> ToCheck(this IQueryable<User> queryable, int age, bool valueToCheck = true)
{
    return queryable.Where(ToBeReviewed(age, valueToCheck));
}

public static Expression<Func<User, bool>> ToCheck(int age, bool valueToCheck = true)
{
    return au => au.Status == UserStatus.Inactive
        || au.Status == UserStatus.Active &&
        au.Age.HasValue && au.Age.Value > age;
}

I am then able to use them in queries:

var globalQuery = db.Users.ToCheck(value);

And also in selects:

var func = EntityExtensions.ToCheck(value);

var q = db.Department.Select(d => new
{
    OrdersTotal = d.Orders.Sum(o => o.Price),
    ToCheck = d.Users.AsQueryable().Count(func),
})

What I am trying to achieve is to actually use the same expression/function within a select, to evaluate it for each row.

var usersQuery = query.Select(au => new {
    Id = au.Id,
    Email = au.Email,
    Status = au.Status.ToString(),
    ToBeChecked = ???, // USE FUNCTION HERE
    CreationTime = au.CreationTime,
    LastLoginTime = au.LastLoginTime,
});

I am pretty that threre would be a way using plain EF capabilities or LINQKit, but can't find it.

Upvotes: 3

Views: 3483

Answers (2)

Konstantin Zolin
Konstantin Zolin

Reputation: 487

I want to add one more example:

Expression<Func<AddressObject, string, string>> selectExpr = (n, a) => n == null ? "[no address]" : n.OFFNAME + a;

var result = context.AddressObjects.AsExpandable().Select(addressObject => selectExpr.Invoke(addressObject, "1"));

Also, expression can be static in a helper. p.s. please not forget to add "using LinqKit;" and use "AsExpandable".

Upvotes: 0

Benjamin Soulier
Benjamin Soulier

Reputation: 2263

Answering my own question :)

As pointed by @ivan-stoev, the use of Linqkit was the solution:

var globalQueryfilter = db.Users.AsExpandable.Where(au => au.Department == "hq");

var func = EntityExtensions.ToCheck(value);
var usersQuery = globalQueryfilter.Select(au => new
{
    Id = au.Id,
    Email = au.Email,
    Status = au.Status.ToString(),
    ToBeChecked = func.Invoke(au),
    CreationTime = au.CreationTime,
    LastLoginTime = au.LastLoginTime,
});
return appUsersQuery;

It's required to use the AsExpandable extension method from Linqkit along with Invoke with the function in the select method.

Upvotes: 3

Related Questions