[英]MVC, Entity Framework - Is there a better way to filter items?
I'm using a separate class to keep the filter options: 我正在使用一个单独的类来保留过滤器选项:
public class FilterViewModel
{
public string UserName { get; set; }
public int? TownId { get; set; }
...
}
In the action I use a predicate which takes the filter as a parameter.That way the "Where" method returns IEnumerable instaed of IQuerable: 在操作中,我使用了一个谓词,该谓词将过滤器作为参数。这样,“ 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;
}
}
...
}
This worked until in ProfileViewModel I implemented database DateTime? 这一直有效,直到在ProfileViewModel中我实现了数据库DateTime? operation in the mapping:
映射中的操作:
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))
}
}
Then on the "Where" method in the action an error appears: 然后在操作中的“ Where”方法上出现错误:
[NotSupportedException: This function can only be invoked from LINQ to Entities.] System.Data.Entity.DbFunctions.DiffMinutes(Nullable 1 timeValue1, Nullable
1 timeValue2) +56 [NotSupportedException:此函数只能从LINQ到Entities调用。] System.Data.Entity.DbFunctions.DiffMinutes(可空
1 timeValue1, Nullable
1 timeValue2)+56
I'm also wondering does in this case, IEnumerable "Where" copys all the database items in the memory and then filters them? 我也想知道在这种情况下IEnumerable“哪里”会复制内存中的所有数据库项,然后对其进行过滤吗?
Thanks in advance! 提前致谢!
EF expects Expression<Func<T,bool>>
, but you are returning Func<T,bool>
EF期望
Expression<Func<T,bool>>
,但是您要返回Func<T,bool>
You have to change it to following 您必须将其更改为以下内容
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;
}
In case if you want to apply multiple filters, then you will have to filter IQueryable itself. 如果要应用多个过滤器,则必须过滤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;
}
In order to run SQL and related operations on server, you have to apply filter on IQueryable which will be executed on server, instead of loading all them locally and then try to filter it. 为了在服务器上运行SQL和相关操作,您必须在将在服务器上执行的IQueryable上应用过滤器,而不是在本地加载所有过滤器然后尝试对其进行过滤。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.