MVC,实体框架 - 有更好的方法来过滤项目吗?

时间:2015-03-07 14:55:22

标签: c# asp.net-mvc linq entity-framework

我正在使用单独的类来保留过滤器选项:

    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”复制内存中的所有数据库项目然后过滤它们?

提前致谢!

1 个答案:

答案 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应用过滤器,而不是在本地加载它们,然后尝试过滤它。