0

I am looking to share some very simple logic across multiple queries in Entity Framework. Say I have the following models

public class User
{
    // user properties
    public ICollection<UserRole> Roles { get; set; }
}

public class UserRole : IDateRestricted
{
    public RoleType Type { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime? EndDate { get; set; }
}

public interface IDateRestricted
{
    DateTime StartDate { get; set; }
    DateTime? EndDate { get; set; }
}

If I was using normal LINQ I could create a simple extension method that would allow me to determine if the role was currently active.

public static class DateRestrictedExtensions
{
    public static Boolean IsActive(this IDateRestricted entity)
    {
        return entity.StartDate <= DateTime.Now && (entity.EndDate == null || entity.EndDate > DateTime.Now);
    }
}

and I could use it like so.

var admins = users.Where(x => x.Roles.Any(role => role.Type == RoleType.Admin && role.IsActive()));

With entity framework this fails with the dreaded:

LINQ to Entities does not recognize the method Boolean IsActive(Domain.Interfaces.IDateRestricted) method, and this method cannot be translated into a store expression.

Is there a way that I can share this logic and have LINQ to Entities support it when querying?

2
  • You will need to use LINQKit or roll your own equivalent. Commented Jun 12, 2018 at 23:24
  • You could also create extensions that return Expression<Func> types but you would need to pass them as the whole parameter of the e.g. Any. Commented Jun 12, 2018 at 23:31

1 Answer 1

1

You should use Expression<Func<IDateRestricted, bool>> instead of Func<IDateRestricted, bool> - presented exception's description exactly points to it:

public static class DateRestrictedExtensions
{
    public static Expression<Func<IDateRestricted, bool>> IsActive()
    {
        return entity => entity.StartDate <= DateTime.Now 
                         && (entity.EndDate == null || entity.EndDate > DateTime.Now);
    }
}

var admins = users.Where(x => x.Roles.AsQueryable().Where(role.Type == RoleType.Admin)
                                   .Any(DateRestrictedExtensions.IsActive()));
Sign up to request clarification or add additional context in comments.

5 Comments

Thought about this but the .Any() method does not accept an expression it would seem
Adding .AsQueryable() to the roles collection allows it to work. Also you must include the static class name in the method call. If you update the answer with these I will accept it.
@AaronRoberts, can you explain, why it is not working without .AsQueryable(). What problem did you face?
there is no error because it doesn’t build. The LINQ extension methods on an ICollection don’t accept expression functions as a parameter.
@AaronRoberts, yes, indeed, fixed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.