【问题标题】:Entity Framework: Unable to call .OrderBy on calculated field IQueryable实体框架:无法在计算字段 IQueryable 上调用 .OrderBy
【发布时间】:2020-06-07 09:20:14
【问题描述】:

我目前正在努力弄清楚如何通过仅具有 getter 的字段对查询进行排序。我有一个 IQueryable 正在构建如下:

var referrals = db.Referrals
                        .Include(x => x.Doctor)
                        .Include(x => x.OfficeLocation)
                        .Where(x => (vm.OfficeLocationSelection == -1 ? true : x.OfficeLocationId == vm.OfficeLocationSelection) &&
                        string.IsNullOrEmpty(vm.SearchTerm) ? true : x.Doctor.Name.ToLower().Contains(vm.SearchTerm.ToLower()))
                        .GroupBy(x => x.Doctor)
                        .Select(x => new ReferralGridRowViewModel
                        {
                            DoctorName = x.Key.Name,
                            January = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 1 && y.Date.Year == DateTime.Now.Year).Count(),
                            February = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 2 && y.Date.Year == DateTime.Now.Year).Count(),
                            March = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 3 && y.Date.Year == DateTime.Now.Year).Count(),
                            April = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 4 && y.Date.Year == DateTime.Now.Year).Count(),
                            May = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 5 && y.Date.Year == DateTime.Now.Year).Count(),
                            June = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 6 && y.Date.Year == DateTime.Now.Year).Count(),
                            July = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 7 && y.Date.Year == DateTime.Now.Year).Count(),
                            August = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 8 && y.Date.Year == DateTime.Now.Year).Count(),
                            September = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 9 && y.Date.Year == DateTime.Now.Year).Count(),
                            October = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 10 && y.Date.Year == DateTime.Now.Year).Count(),
                            November = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 11 && y.Date.Year == DateTime.Now.Year).Count(),
                            December = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 12 && y.Date.Year == DateTime.Now.Year).Count()
                        });

ReferralGridRowViewModel 如下所示(注意 YearToDate 属性):

public class ReferralGridRowViewModel
    {
        public string DoctorName { get; set; }

        public int January { get; set; }

        public int February { get; set; }

        public int March { get; set; }

        public int April { get; set; }

        public int May { get; set; }

        public int June { get; set; }

        public int July { get; set; }

        public int August { get; set; }

        public int September { get; set; }

        public int October { get; set; }

        public int November { get; set; }

        public int December { get; set; }

        public int YearToDate {
            get {
                return (January + February + March + April + May + June + July + August + September + October + November + December);
            }
        }
    }

当我尝试调用以下内容时:

referrals = referrals.OrderByDescending(x => x.YearToDate);

然后我收到以下异常:

LINQ to 不支持指定的类型成员“YearToDate” 实体。只有初始化器、实体成员和实体导航 支持属性。

当查询实际在这一行执行时:

referralRows = referrals.Skip(vm.Skip).Take(vm.PageSize).ToList();

我怎样才能以高效的方式克服这个问题?我宁愿不在 YearToDate 的数据库中添加一列,因为它是多余的,我不能事先.ToList 一切然后排序,因为数据库中有数百万条记录,这将对性能造成重大影响

【问题讨论】:

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


【解决方案1】:

您可以添加[NotMapped] 属性:

using System.ComponentModel.DataAnnotations.Schema;
...

public class ReferralGridRowViewModel
{
    ...

    [NotMapped]
    public int YearToDate {
    get {
      return (January + February + March + April + May + June + July + August + September + October + November + December);
    }
  }
}

它向 EF 指示忽略 db 端的属性。请参阅文档:
https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.schema.notmappedattribute?view=netframework-4.8

【讨论】:

  • 这并不能解决我的问题。此列在数据库中不存在 - 仅在我的查询中选择的 dto 中,EF 不会让我在此列上排序,因为它在 db 中不存在
  • @GregH 是的,我重新阅读了您的问题,并注意到我跳过了有关无法在应用程序端进行排序的部分,抱歉。如果是这种情况,我看到的唯一选择是以类似于以下的方式进行操作:...GroupBy(x => x.Doctor) .OrderByDescending(x => x.Count(y => y.DoctorId == x.Key.Id && y.Date.Year == DateTime.Now.Year)) .Select(x => new ReferralGridRowViewModel({...}); 尽管我不能肯定地说 EF 能够将其转换为 SQL,其中万一它将再次在应用程序端执行,这对您来说是不可以的。
  • 尝试添加 [NotMapped] 并将您的设置器替换为 { get; set; } 并将 YearToDate = x.Count() 添加到 Select
【解决方案2】:

在选择实际的ReferralGridRowViewModel 之前,我可以通过检查医生ID 和年份的分组来按YearToDate 记录排序,如下所示:

                    var referralsGrouping = db.Referrals
                        .Include(x => x.Doctor)
                        .Include(x => x.OfficeLocation)
                        .Where(x => (vm.OfficeLocationSelection == -1 ? true : x.OfficeLocationId == vm.OfficeLocationSelection) &&
                        string.IsNullOrEmpty(vm.SearchTerm) ? true : x.Doctor.Name.ToLower().Contains(vm.SearchTerm.ToLower()))
                        .GroupBy(x => x.Doctor);

                    if (!string.IsNullOrEmpty(vm.SortColumn))
                    {
                        if (vm.SortColumn == "YearToDate")
                        {
                            if (vm.SortDirection == SortDirectionType.Descending)
                            {
                                referralsGrouping = referralsGrouping.OrderByDescending(x => x.Count(y => y.DoctorId == x.Key.Id && y.Date.Year == DateTime.Now.Year));
                            }
                            else
                            {
                                referralsGrouping = referralsGrouping.OrderBy(x => x.Count(y => y.DoctorId == x.Key.Id && y.Date.Year == DateTime.Now.Year));
                            }
                        }
                    }

                    var referrals = referralsGrouping
                    .Select(x => new ReferralGridRowViewModel
                    {
                        DoctorName = x.Key.Name,
                        January = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 1 && y.Date.Year == DateTime.Now.Year).Count(),
                        February = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 2 && y.Date.Year == DateTime.Now.Year).Count(),
                        March = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 3 && y.Date.Year == DateTime.Now.Year).Count(),
                        April = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 4 && y.Date.Year == DateTime.Now.Year).Count(),
                        May = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 5 && y.Date.Year == DateTime.Now.Year).Count(),
                        June = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 6 && y.Date.Year == DateTime.Now.Year).Count(),
                        July = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 7 && y.Date.Year == DateTime.Now.Year).Count(),
                        August = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 8 && y.Date.Year == DateTime.Now.Year).Count(),
                        September = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 9 && y.Date.Year == DateTime.Now.Year).Count(),
                        October = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 10 && y.Date.Year == DateTime.Now.Year).Count(),
                        November = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 11 && y.Date.Year == DateTime.Now.Year).Count(),
                        December = x.Where(y => y.DoctorId == x.Key.Id && y.Date.Month == 12 && y.Date.Year == DateTime.Now.Year).Count()
                    });

                if (!string.IsNullOrEmpty(vm.SortColumn))
                {
                    if (vm.SortColumn == "DoctorName")
                    {
                        if (vm.SortDirection == SortDirectionType.Descending)
                        {
                            referrals = referrals.OrderByDescending(x => x.DoctorName);
                        }
                        else
                        {
                            referrals = referrals.OrderBy(x => x.DoctorName);
                        }
                    }
                    //other vm sort columns
                }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 1970-01-01
    • 2017-03-12
    • 2013-06-06
    相关资源
    最近更新 更多