我正在使用一个单独的类来保留过滤器选项:
public class FilterViewModel
{
public string UserName { get; set; }
public int? TownId { get; set; }
...
}
在操作中,我使用了一个将过滤器作为参数的谓词。这样,"Where"方法返回IQuerable的IEnumerable instaed:
public ActionResult FilterProfiles(FilterViewModel filter)
{
var profiles = this.Data.Profiles.All()
.Where(Predicate(filter))
.OrderBy(p => p.ProfileUser.UserName).AsQueryable()
.Project()
.To<ProfileViewModel>()
.ToList();
}
private static Func<UserProfile, bool> Predicate(FilterViewModel f)
{
return p => (CompareFilter(p, f));
}
private static bool CompareFilter(UserProfile profile, FilterViewModel filter)
{
if (filter.FirstName != null)
{
if (profile.FirstName != null)
{
if (profile.FirstName.CompareTo(filter.FirstName) != 0)
{
return false;
}
}
...
}
这一直有效,直到在 ProfileViewModel 中,我在映射中实现了数据库 DateTime? 操作:
public class ProfileViewModel : IHaveCustomMappings
{
...
public bool IsUserOnline { get; set; }
...
public void CreateMappings(IConfiguration configuration)
{
configuration.CreateMap<UserProfile, ProfileViewModel>()
.ForMember(m => m.IsUserOnline, opt => opt.MapFrom(p =>
DbFunctions.DiffMinutes(p.ProfileUser.LastActionTime, DateTime.Now) < 5 ? true : false))
}
}
然后在操作中的"Where"方法上出现错误:
[NotSupportedException:此函数只能从 LINQ 调用到实体。 System.Data.Entity.DbFunctions.DiffMinutes(Nullable 1 timeValue1, Nullable
1 timeValue2) +56
我也想知道在这种情况下,IEnumerable "Where" 是否复制内存中的所有数据库项目,然后过滤它们?
提前感谢!
EF 期望Expression<Func<T,bool>>
,但您返回的是Func<T,bool>
您必须将其更改为以下
private static Expression<Func<UserProfile, bool>>
Predicate(FilterViewModel f)
{
return CompareFilter(f));
}
private static Expression<Func<UserProfile, bool>>
CompareFilter(FilterViewModel filter)
{
if (filter.FirstName != null)
{
return p => p.FirstName == filter.FirstName;
}
...
// this means nothing to compare,
// return all records...
return p => true;
}
如果您想应用多个过滤器,那么您将不得不过滤 IQueryable 本身。
private static IQueryable<UserProfile>
Predicate(IQueryable<UserProfile> q, FilterViewModel f)
{
if (filter.FirstName != null)
{
q = q.Where( p => p.FirstName == filter.FirstName );
}
if (filter.LastName != null)
{
q = q.Where( p => p.LastName == filter.LastName );
}
...
// return all records...
return q;
}
为了在服务器上运行SQL和相关操作,您必须在IQueryable上应用过滤器,该过滤器将在服务器上执行,而不是在本地加载所有过滤器,然后尝试过滤它。