我正在使用单独的类来保留过滤器选项:
public class FilterViewModel
{
public string UserName { get; set; }
public int? TownId { get; set; }
...
}
在动作中我使用一个谓词,它将过滤器作为参数。“Where”方法返回IEnumerable instueed的IQuerable:
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”复制内存中的所有数据库项目然后过滤它们?
提前致谢!
答案 0 :(得分:2)
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应用过滤器,而不是在本地加载它们,然后尝试过滤它。