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?
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()));